init files
This commit is contained in:
commit
8197a022bd
1409 changed files with 139317 additions and 0 deletions
271
loader/src/Makefile
Executable file
271
loader/src/Makefile
Executable file
|
|
@ -0,0 +1,271 @@
|
|||
|
||||
INSTALL ?= 1000
|
||||
RESIDENT ?= 0200
|
||||
TRANSIENT ?= 4000
|
||||
ZP ?= e0
|
||||
|
||||
export _PLATFORM_ INSTALL RESIDENT TRANSIENT ZP
|
||||
|
||||
ifeq ($(PLATFORM),)
|
||||
_PLATFORM_ = c64
|
||||
else ifeq ($(PLATFORM),c128)
|
||||
_PLATFORM_ = c128
|
||||
else ifeq ($(PLATFORM),c16)
|
||||
_PLATFORM_ = c16
|
||||
else ifeq ($(PLATFORM),c116)
|
||||
_PLATFORM_ = c16
|
||||
else ifeq ($(PLATFORM),plus4)
|
||||
_PLATFORM_ = c16
|
||||
else
|
||||
_PLATFORM_ = $(PLATFORM)
|
||||
endif
|
||||
|
||||
ifneq ($(_PLATFORM_),c64)
|
||||
ifneq ($(_PLATFORM_),c128)
|
||||
ifneq ($(_PLATFORM_),c16)
|
||||
$(error invalid platform $(_PLATFORM_) specified)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
TOP ?= .
|
||||
|
||||
SVNVERSION = svnversion
|
||||
ifneq ($(wildcard ../../.svn/format),)
|
||||
VERSION = $(shell $(SVNVERSION) | tr -d [:cntrl:])
|
||||
else
|
||||
VERSION = $(shell $(GREP) -oP 'VERSION_STRING "\K[^"]+' ../version.inc)
|
||||
endif
|
||||
|
||||
CD = cd
|
||||
ECHO = echo
|
||||
PRINTF = printf
|
||||
CAT = cat
|
||||
CP = cp
|
||||
MV = mv
|
||||
RM = rm -f
|
||||
MKDIR = mkdir
|
||||
RMDIR = rmdir
|
||||
GREP = ggrep
|
||||
|
||||
AS = ca65
|
||||
LD = ld65
|
||||
AR = ar65
|
||||
VICE = x64
|
||||
C1541 = c1541
|
||||
|
||||
PERL = perl
|
||||
ZIP = zip -9
|
||||
|
||||
INCDIR = $(TOP)/../../shared
|
||||
LDRINC = $(TOP)/../include
|
||||
|
||||
DECOMPDIR = $(TOP)/decompress
|
||||
DRIVESDIR = $(TOP)/drives
|
||||
HALDIR = $(TOP)/hal
|
||||
|
||||
BUILDDIR = $(TOP)/../build
|
||||
INTERMDIR = $(TOP)/../build/intermediate
|
||||
|
||||
ifneq ($(EXTCONFIGPATH),)
|
||||
CONFIG = $(EXTCONFIGPATH)/loaderconfig.inc
|
||||
else
|
||||
CONFIG = $(LDRINC)/config.inc
|
||||
endif
|
||||
|
||||
INSTALLDEPS = $(CONFIG) $(BUILDDIR) $(INTERMDIR) \
|
||||
$(DRIVESDIR)/drivecode-common.inc $(DRIVESDIR)/drivecode1541.s $(DRIVESDIR)/drivecode1571.s $(DRIVESDIR)/drivecode1581.s \
|
||||
$(HALDIR)/hal.inc $(HALDIR)/hal-c64-c128.inc $(HALDIR)/hal-c16.inc \
|
||||
install.s \
|
||||
$(LDRINC)/loader.inc \
|
||||
$(TOP)/../version.inc Makefile
|
||||
|
||||
RESIDENTDEPS = $(CONFIG) $(BUILDDIR) $(INTERMDIR) \
|
||||
$(DECOMPDIR)/bitnaxdecomp.s \
|
||||
$(DECOMPDIR)/b2decomp.s \
|
||||
$(DECOMPDIR)/doynaxdecomp.s \
|
||||
$(DECOMPDIR)/exodecomp.s \
|
||||
$(DECOMPDIR)/lcdecomp.s \
|
||||
$(DECOMPDIR)/lzsa2decomp.s \
|
||||
$(DECOMPDIR)/ncdecomp.s \
|
||||
$(DECOMPDIR)/pudecomp.s \
|
||||
$(DECOMPDIR)/subsizerdecomp.s \
|
||||
$(DECOMPDIR)/tcdecomp.s \
|
||||
$(DECOMPDIR)/zx0decomp.s \
|
||||
$(HALDIR)/hal.inc $(HALDIR)/hal-c64-c128.inc $(HALDIR)/hal-c16.inc \
|
||||
resident.s \
|
||||
customdrivecode.s \
|
||||
save.s \
|
||||
$(LDRINC)/loader.inc \
|
||||
$(TOP)/../version.inc Makefile
|
||||
|
||||
BINDEPS = $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc $(BUILDDIR)/loader-$(_PLATFORM_).prg $(CONFIG)
|
||||
|
||||
# allow undocumented opcodes
|
||||
ifeq ($(_PLATFORM_),c64)
|
||||
AS_FLAGS = --cpu 6502X
|
||||
else ifeq ($(_PLATFORM_),c128)
|
||||
AS_FLAGS = --cpu 6502X
|
||||
else ifeq ($(_PLATFORM_),c16)
|
||||
AS_FLAGS = --cpu 6502X
|
||||
else
|
||||
# do not allow undocumented opcodes
|
||||
AS_FLAGS = --cpu 6502
|
||||
endif
|
||||
|
||||
AS_FLAGS += -g # include symbols in object files
|
||||
ifeq ($(_PLATFORM_),c16)
|
||||
AS_FLAGS += -t c16 -D PLATFORM=16
|
||||
else ifeq ($(_PLATFORM_),c128)
|
||||
AS_FLAGS += -t c128 -D PLATFORM=128
|
||||
else
|
||||
AS_FLAGS += -t c64 -D PLATFORM=64
|
||||
endif
|
||||
AS_FLAGS += -I $(TOP)/. -I $(INCDIR) -I $(LDRINC)
|
||||
ifneq ($(EXTCONFIGPATH),)
|
||||
AS_FLAGS += -D EXTCONFIGPATH -I $(EXTCONFIGPATH)
|
||||
endif
|
||||
|
||||
.PHONY: lib prg bin binary prgzip binzip binaryzip customdrivecode save
|
||||
|
||||
default: prg
|
||||
|
||||
all: lib prg
|
||||
|
||||
# use these targets to build loader-<PLATFORM>.prg and install-<PLATFORM>.prg along with loadersymbols-<PLATFORM>.inc
|
||||
prg bin binary: $(BINDEPS)
|
||||
@$(ECHO) "Usage: $(MAKE) prg INSTALL=<install hexaddress> RESIDENT=<core hexaddress> ZP=<zp hexaddress> [PROJECT=<project>]"
|
||||
@$(ECHO) "INSTALL=\$$$(INSTALL)"
|
||||
@$(ECHO) "RESIDENT=\$$$(RESIDENT)"
|
||||
@$(ECHO) "ZP=\$$$(ZP)"
|
||||
@$(ECHO) "PROJECT=$(PROJECT)"
|
||||
$(CAT) $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc
|
||||
|
||||
prgzip binzip binaryzip: $(BUILDDIR)/loader-$(_PLATFORM_).zip
|
||||
|
||||
customdrivecode: $(BUILDDIR)/customdrivecode-$(_PLATFORM_).prg
|
||||
@$(ECHO) "Usage: $(MAKE) customdrivecode INSTALL=<install hexaddress> RESIDENT=<core hexaddress> TRANSIENT=<plug-ins hexaddress> ZP=<zp hexaddress> [PROJECT=<project>]"
|
||||
@$(ECHO) "INSTALL=\$$$(INSTALL)"
|
||||
@$(ECHO) "RESIDENT=\$$$(RESIDENT)"
|
||||
@$(ECHO) "TRANSIENT=\$$$(TRANSIENT)"
|
||||
@$(ECHO) "ZP=\$$$(ZP)"
|
||||
@$(ECHO) "PROJECT=$(PROJECT)"
|
||||
$(CAT) $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc
|
||||
|
||||
save: $(BUILDDIR)/save-$(_PLATFORM_).prg
|
||||
@$(ECHO) "Usage: $(MAKE) save INSTALL=<install hexaddress> RESIDENT=<core hexaddress> TRANSIENT=<plug-ins hexaddress> ZP=<zp hexaddress> [PROJECT=<project>]"
|
||||
@$(ECHO) "INSTALL=\$$$(INSTALL)"
|
||||
@$(ECHO) "RESIDENT=\$$$(RESIDENT)"
|
||||
@$(ECHO) "TRANSIENT=\$$$(TRANSIENT)"
|
||||
@$(ECHO) "ZP=\$$$(ZP)"
|
||||
@$(ECHO) "PROJECT=$(PROJECT)"
|
||||
$(CAT) $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc
|
||||
|
||||
lib: $(BUILDDIR)/loader-$(_PLATFORM_).lib
|
||||
|
||||
|
||||
$(TOP)/../version.inc:
|
||||
$(MAKE) -C $(TOP)/.. version.inc
|
||||
|
||||
|
||||
# directory targets
|
||||
|
||||
$(BUILDDIR):
|
||||
$(MKDIR) $@
|
||||
|
||||
$(INTERMDIR):
|
||||
$(MKDIR) $@
|
||||
|
||||
|
||||
# object targets
|
||||
|
||||
$(INTERMDIR)/install-$(_PLATFORM_).o: $(INSTALLDEPS)
|
||||
$(AS) $(AS_FLAGS) -I $(INTERMDIR) -o $@ install.s # allow undocumented opcodes for drive code
|
||||
|
||||
$(INTERMDIR)/customdrivecode-$(_PLATFORM_).o: $(RESIDENTDEPS)
|
||||
$(AS) $(AS_FLAGS) -o $@ customdrivecode.s
|
||||
|
||||
$(INTERMDIR)/save-$(_PLATFORM_).o: $(RESIDENTDEPS)
|
||||
$(AS) $(AS_FLAGS) -o $@ save.s
|
||||
|
||||
$(INTERMDIR)/resident-$(_PLATFORM_).o: $(RESIDENTDEPS)
|
||||
$(AS) $(AS_FLAGS) -o $@ resident.s
|
||||
|
||||
|
||||
# binary targets
|
||||
|
||||
.PHONY: $(INTERMDIR)/binary.link
|
||||
.PHONY: $(BUILDDIR)/loader-$(_PLATFORM_).prg $(INTERMDIR)/loader-nonreloc-$(_PLATFORM_).o
|
||||
.PHONY: $(BUILDDIR)/install-$(_PLATFORM_).prg $(INTERMDIR)/install-nonreloc-$(_PLATFORM_).o
|
||||
.PHONY: $(BUILDDIR)/customdrivecode-$(_PLATFORM_).prg $(INTERMDIR)/customdrivecode-nonreloc-$(_PLATFORM_).o
|
||||
.PHONY: $(BUILDDIR)/save-$(_PLATFORM_).prg $(INTERMDIR)/save-nonreloc-$(_PLATFORM_).o
|
||||
.PHONY: $(INTERMDIR)/loader.map $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc
|
||||
|
||||
$(INTERMDIR)/loader-nonreloc-$(_PLATFORM_).o: $(RESIDENTDEPS)
|
||||
$(AS) $(AS_FLAGS) -D RESIADDR=0x$(RESIDENT) -o $@ resident.s
|
||||
|
||||
$(INTERMDIR)/install-nonreloc-$(_PLATFORM_).o: $(RESIDENTDEPS)
|
||||
$(AS) $(AS_FLAGS) -D INSTADDR=0x$(INSTALL) -o $@ install.s
|
||||
|
||||
$(INTERMDIR)/binary.link: Makefile
|
||||
$(PERL) make-linkfile.pl $(_PLATFORM_) $(ZP) $(INSTALL) $(RESIDENT) $(TRANSIENT) > $@
|
||||
$(CAT) $@
|
||||
|
||||
$(BUILDDIR)/loader-$(_PLATFORM_).prg: $(INTERMDIR)/loader-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/install-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/binary.link
|
||||
$(LD) -C $(INTERMDIR)/binary.link -vm -m $(INTERMDIR)/loader-$(_PLATFORM_).map $(INTERMDIR)/loader-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/install-nonreloc-$(_PLATFORM_).o
|
||||
$(RM) a.out
|
||||
|
||||
$(BUILDDIR)/install-$(_PLATFORM_).prg: $(BUILDDIR)/loader-$(_PLATFORM_).prg
|
||||
|
||||
$(INTERMDIR)/loader-$(_PLATFORM_).map: $(BUILDDIR)/install-$(_PLATFORM_).prg
|
||||
|
||||
|
||||
$(INTERMDIR)/customdrivecode-nonreloc-$(_PLATFORM_).o: customdrivecode.s
|
||||
$(AS) $(AS_FLAGS) -D TRNSADDR=0x$(TRANSIENT) -o $@ $^
|
||||
|
||||
$(BUILDDIR)/customdrivecode-$(_PLATFORM_).prg: $(INTERMDIR)/binary.link $(INTERMDIR)/customdrivecode-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/loader-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/install-nonreloc-$(_PLATFORM_).o
|
||||
$(LD) -vm -m $(INTERMDIR)/loader-$(_PLATFORM_).map -C $^
|
||||
$(MV) $(BUILDDIR)/transient-$(_PLATFORM_).prg $@
|
||||
$(PERL) make-loadersymbolsinc.pl $(VERSION) $(_PROJECT_) $(INTERMDIR)/loader-$(_PLATFORM_).map > $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc
|
||||
|
||||
$(INTERMDIR)/save-nonreloc-$(_PLATFORM_).o: save.s
|
||||
$(AS) $(AS_FLAGS) -D TRNSADDR=0x$(TRANSIENT) -o $@ $^
|
||||
|
||||
$(BUILDDIR)/save-$(_PLATFORM_).prg: $(INTERMDIR)/binary.link $(INTERMDIR)/save-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/customdrivecode-$(_PLATFORM_).o $(INTERMDIR)/loader-nonreloc-$(_PLATFORM_).o $(INTERMDIR)/install-nonreloc-$(_PLATFORM_).o
|
||||
$(LD) -vm -m $(INTERMDIR)/loader-$(_PLATFORM_).map -C $^
|
||||
$(MV) $(BUILDDIR)/transient-$(_PLATFORM_).prg $@
|
||||
$(PERL) make-loadersymbolsinc.pl $(VERSION) $(_PROJECT_) $(INTERMDIR)/loader-$(_PLATFORM_).map > $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc
|
||||
|
||||
ifeq ($(PROJECT),)
|
||||
_PROJECT_ = loader
|
||||
else
|
||||
_PROJECT_ = $(PROJECT)
|
||||
endif
|
||||
|
||||
$(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc: $(INTERMDIR)/loader-$(_PLATFORM_).map
|
||||
$(PERL) make-loadersymbolsinc.pl $(VERSION) $(_PROJECT_) $^ > $@
|
||||
|
||||
$(BUILDDIR)/loader-$(_PLATFORM_).zip: $(BINDEPS)
|
||||
$(CD) $(BUILDDIR) \
|
||||
&& $(CP) $(BUILDDIR)/loader-$(_PLATFORM_).prg $(INTERMDIR)/loader.prg && $(ZIP) -j $@ $(INTERMDIR)/loader.prg \
|
||||
&& $(CP) $(BUILDDIR)/install-$(_PLATFORM_).prg $(INTERMDIR)/install.prg && $(ZIP) -j $@ $(INTERMDIR)/install.prg \
|
||||
&& $(CP) $(BUILDDIR)/loadersymbols-$(_PLATFORM_).inc $(INTERMDIR)/loadersymbols.inc && $(ZIP) -j $@ $(INTERMDIR)/loadersymbols.inc
|
||||
|
||||
|
||||
# loader-$(_PLATFORM_).lib library target
|
||||
|
||||
$(BUILDDIR)/loader-$(_PLATFORM_).lib: $(INTERMDIR)/resident-$(_PLATFORM_).o $(INTERMDIR)/install-$(_PLATFORM_).o $(INTERMDIR)/customdrivecode-$(_PLATFORM_).o $(INTERMDIR)/save-$(_PLATFORM_).o
|
||||
$(AR) a $@ $^
|
||||
|
||||
|
||||
clean:
|
||||
-$(RM) \
|
||||
$(INTERMDIR)/* \
|
||||
$(BUILDDIR)/loader-c64.lib \
|
||||
$(BUILDDIR)/loader-c64.prg $(BUILDDIR)/install-c64.prg $(BUILDDIR)/loadersymbols-c64.inc \
|
||||
$(BUILDDIR)/loader-c128.lib \
|
||||
$(BUILDDIR)/loader-c128.prg $(BUILDDIR)/install-c128.prg $(BUILDDIR)/loadersymbols-c128.inc \
|
||||
$(BUILDDIR)/loader-c16.lib \
|
||||
$(BUILDDIR)/loader-c16.prg $(BUILDDIR)/install-c16.prg $(BUILDDIR)/loadersymbols-c16.inc
|
||||
-$(RMDIR) $(INTERMDIR)
|
||||
660
loader/src/customdrivecode.s
Normal file
660
loader/src/customdrivecode.s
Normal file
|
|
@ -0,0 +1,660 @@
|
|||
|
||||
__NO_CUSTOMDRIVECODE_SYMBOLS_IMPORT = 1
|
||||
.include "loader.inc"
|
||||
|
||||
.include "drives/drivecode-common.inc"
|
||||
.include "hal/hal.inc"
|
||||
|
||||
.include "cpu.inc"
|
||||
.scope drive
|
||||
.include "via.inc"
|
||||
.endscope
|
||||
.include "cia.inc"
|
||||
|
||||
.segment "DISKIO_PLUGIN_ZP" : zeropage
|
||||
|
||||
CUSTOMPARAM: .res 2
|
||||
DRVCODEOFS: .res 1
|
||||
DRVCODEPTR: .res 2
|
||||
BUFFERPTR: .res 2
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
DRIVETYPE: .res 1
|
||||
.endif; ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
UPLOADENTR: .res 2
|
||||
UPLOADTO: .res 2
|
||||
UPLOADCNT: .res 2
|
||||
UPLOADPTR: .res 2
|
||||
|
||||
plugin_zp_last = * - 1
|
||||
.export plugin_zp_last
|
||||
|
||||
.segment "DISKIO_PLUGIN"
|
||||
|
||||
.ifdef TRNSADDR
|
||||
.org TRNSADDR - 2
|
||||
.word * + 2; load address
|
||||
.endif
|
||||
|
||||
.export swapdrvcod
|
||||
|
||||
swapdrvcod: stx CUSTOMPARAM
|
||||
sty CUSTOMPARAM + 1
|
||||
|
||||
stx DRVCODEPTR
|
||||
sty DRVCODEPTR + 1
|
||||
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
|
||||
lda #$80
|
||||
sta DRIVETYPE
|
||||
BRANCH_IF_INSTALLED :+
|
||||
lda #diskio::status::DEVICE_INCOMPATIBLE
|
||||
sec
|
||||
rts
|
||||
:
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
ldy #swapparams::buffer
|
||||
lda (CUSTOMPARAM),y
|
||||
sta BUFFERPTR
|
||||
sta bufmain41
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
sta bufmain71
|
||||
sta bufmain81
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
iny
|
||||
lda (CUSTOMPARAM),y
|
||||
sta BUFFERPTR + 1
|
||||
sta bufmain41 + 1
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
sta bufmain71 + 1
|
||||
sta bufmain81 + 1
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
CLEAR
|
||||
|
||||
: SET_FLAGS_N_DATA_V_CLK
|
||||
bvc :-
|
||||
|
||||
ldy #$ff
|
||||
: iny
|
||||
lda trampoline,y
|
||||
jsr sendbyte
|
||||
bne :-
|
||||
|
||||
ldy #swapparams::drivecode41
|
||||
jsr prepmove
|
||||
ldx #drivecode::from - 1
|
||||
: lda UPLOADENTR,x
|
||||
sta trampoln41 + payldprm41 - trmplrun41,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
lda #diskio::drivetype::DRIVES_1541
|
||||
|
||||
SET_FLAGS_N_DATA_V_CLK
|
||||
bvc is1581
|
||||
bmi setdrvtype
|
||||
|
||||
IDLE
|
||||
|
||||
ldy #swapparams::drivecode71
|
||||
jsr prepmove
|
||||
ldx #drivecode::from - 1
|
||||
: lda UPLOADENTR,x
|
||||
sta trampoln71 + payldprm71 - trmplrun71,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #diskio::drivetype::DRIVES_157X
|
||||
bne setdrvtype; jmp
|
||||
|
||||
is1581: IDLE
|
||||
|
||||
ldy #swapparams::drivecode81
|
||||
jsr prepmove
|
||||
ldx #drivecode::from - 1
|
||||
: lda UPLOADENTR,x
|
||||
sta custom81 + payldprm81 - trampoln81,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #diskio::drivetype::DRIVES_1581_CMD
|
||||
|
||||
setdrvtype: sta DRIVETYPE
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
jsr selectdcod
|
||||
|
||||
pha
|
||||
ldy #drivecode::entry
|
||||
jsr prepmove
|
||||
pla
|
||||
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
|
||||
cmp #swapparams::drivecode81
|
||||
bne doupload
|
||||
|
||||
ldy #drivecode::from
|
||||
: lda UPLOADENTR - 1,y
|
||||
jsr sendbyte
|
||||
dey
|
||||
bne :-
|
||||
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
doupload: jsr uploadcode
|
||||
|
||||
ldy #ldrmain41 - drvcode41 - drivecode::length
|
||||
jsr prepmove
|
||||
|
||||
; buffer loader drive code
|
||||
CLEAR
|
||||
|
||||
: SET_FLAGS_N_DATA_V_CLK
|
||||
bvc :-
|
||||
|
||||
ldy #0
|
||||
getdrvcode: jsr receivbyte
|
||||
sta (BUFFERPTR),y
|
||||
iny
|
||||
bne :+
|
||||
inc BUFFERPTR + 1
|
||||
: inc UPLOADCNT
|
||||
bne getdrvcode
|
||||
inc UPLOADCNT + 1
|
||||
bmi getdrvcode
|
||||
|
||||
: SET_FLAGS_N_DATA_V_CLK
|
||||
bpl :-
|
||||
|
||||
; upload custom drive code
|
||||
lda CUSTOMPARAM
|
||||
sta DRVCODEPTR
|
||||
lda CUSTOMPARAM + 1
|
||||
sta DRVCODEPTR + 1
|
||||
ldy DRVCODEOFS
|
||||
jsr uplodpayld
|
||||
|
||||
CLEAR
|
||||
|
||||
OK_CLC
|
||||
rts
|
||||
|
||||
.export restoreldr
|
||||
|
||||
restoreldr:
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
|
||||
lda DRIVETYPE
|
||||
bpl :+
|
||||
lda #diskio::status::DEVICE_INCOMPATIBLE
|
||||
sec
|
||||
rts
|
||||
:
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
INIT_CLEAR_ATN_OUT_CLEAR_CLK_OUT_CLEAR_DATA_OUT
|
||||
CLEAR
|
||||
|
||||
waitrestor: SET_FLAGS_N_DATA_V_CLK
|
||||
bpl waitrestor
|
||||
bvc waitrestor
|
||||
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
|
||||
lda DRIVETYPE
|
||||
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
jsr selectdcod
|
||||
|
||||
ldy #ldrmain41 - drvcode41 - drivecode::length
|
||||
jsr uplodpayld
|
||||
|
||||
INSTALL_IDLE
|
||||
rts
|
||||
|
||||
.export sendbyte
|
||||
|
||||
sendbyte: pha
|
||||
nop; delay
|
||||
SENDBYTE
|
||||
pla
|
||||
rts
|
||||
|
||||
.export receivbyte
|
||||
|
||||
receivbyte: RECEIVEBYTE
|
||||
rts
|
||||
|
||||
selectdcod:
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
|
||||
cmp #diskio::drivetype::DRIVES_157X
|
||||
bne check1581
|
||||
lda #swapparams::drivecode71
|
||||
ldx #.lobyte(drvcode71)
|
||||
ldy #.hibyte(drvcode71)
|
||||
bne dcodselctd; jmp
|
||||
|
||||
check1581: cmp #diskio::drivetype::DRIVES_1581_CMD
|
||||
bne upload1541
|
||||
lda #swapparams::drivecode81
|
||||
ldx #.lobyte(drvcode81)
|
||||
ldy #.hibyte(drvcode81)
|
||||
bne dcodselctd; jmp
|
||||
upload1541:
|
||||
|
||||
.endif; ONLY_1541_AND_COMPATIBLE
|
||||
|
||||
lda #swapparams::drivecode41
|
||||
ldx #.lobyte(drvcode41)
|
||||
ldy #.hibyte(drvcode41)
|
||||
|
||||
dcodselctd: sta DRVCODEOFS
|
||||
stx DRVCODEPTR
|
||||
sty DRVCODEPTR + 1
|
||||
rts
|
||||
|
||||
uplodpayld: jsr prepmove
|
||||
|
||||
uploadcode: ldy #0
|
||||
: lda (UPLOADPTR),y
|
||||
jsr sendbyte
|
||||
iny
|
||||
bne :+
|
||||
inc UPLOADPTR + 1
|
||||
: inc UPLOADCNT
|
||||
bne :--
|
||||
inc UPLOADCNT + 1
|
||||
bmi :--
|
||||
rts
|
||||
|
||||
prepmove: ldx #0
|
||||
: lda (DRVCODEPTR),y
|
||||
iny
|
||||
sta UPLOADENTR,x
|
||||
inx
|
||||
cpx #8
|
||||
bne :-
|
||||
|
||||
;sec
|
||||
lda #0
|
||||
sbc UPLOADCNT
|
||||
sta UPLOADCNT
|
||||
lda #0
|
||||
sbc UPLOADCNT + 1
|
||||
sta UPLOADCNT + 1
|
||||
rts
|
||||
|
||||
trampoline:
|
||||
.scope upload41
|
||||
|
||||
.include "via.inc"
|
||||
|
||||
.org $ef; FILENAME41
|
||||
|
||||
recvtrmpln: DRIVEGETBYTE 1541, trampolinecmp, nozeroes
|
||||
sta $0105,x; BLOCKBUFFER41 + 5
|
||||
inx
|
||||
cpx #custm41end - trampoln41 + 1
|
||||
bne recvtrmpln
|
||||
.byte $ff
|
||||
.word (entry - 1)
|
||||
entry: lda getbytecmp41 + 1
|
||||
sta .lobyte(trampolinecmp + 1)
|
||||
ldx #1
|
||||
ldy VIA1_PRB + 16
|
||||
bcs recvtrmpln; jmp
|
||||
|
||||
.reloc
|
||||
|
||||
;.byte 0; end marker is 0 at drvcode41
|
||||
|
||||
.endscope
|
||||
|
||||
drvcode41: .word 0; entry, not used here
|
||||
.word trmplrun41; to
|
||||
.word custm41end - trampoln41; length
|
||||
.word trampoln41; from
|
||||
|
||||
ldrmain41: .word $0700 + RETURNSIZE41; buffer length
|
||||
bufmain41: .word 0; buffer
|
||||
|
||||
trampoln41:
|
||||
.org $0106; = BLOCKBUFFER41 + 6
|
||||
|
||||
RESTORELOOP41 = $d9; with SENDVAL41
|
||||
RESTOREMAIN41 = RESTORELOOP41 + 1
|
||||
|
||||
trmplrun41: .scope custom41
|
||||
|
||||
.include "drives/drivecode-common.inc"
|
||||
|
||||
.include "via.inc"
|
||||
|
||||
lda #ATNA_OUT | CLK_OUT | DATA_OUT
|
||||
sta VIA1_PRB
|
||||
|
||||
; buffer end of read loop to make space for the receive routine
|
||||
ldx #21 - 1
|
||||
: lda RESTORELOOP41,x
|
||||
sta SECTORLINKTABLE41,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda getbytecmp41 + 1
|
||||
sta customloop + (getbytecmp41 + 1) - getbyte41
|
||||
|
||||
; put receive routine for buffered loader code to zeropage
|
||||
ldx #$0100 - (custmstore - customloop - 3)
|
||||
: lda custmstore - $0100,x
|
||||
sta .lobyte(restorloop - restrloope),x
|
||||
inx
|
||||
bne :-
|
||||
ldx #$0100 - (restrloope - restorloop)
|
||||
: lda restrloope - $0100,x
|
||||
sta $00,x
|
||||
inx
|
||||
bne :-
|
||||
|
||||
lda #ATNA_OUT
|
||||
sta VIA1_PRB
|
||||
lda #CLK_IN | DATA_IN
|
||||
: bit VIA1_PRB
|
||||
bne :-
|
||||
|
||||
SENDVAL41 = RESTORELOOP41
|
||||
|
||||
sendzp: lda $00,x
|
||||
DRIVESENDBYTE 1541, SENDVAL41
|
||||
inx
|
||||
bne sendzp
|
||||
|
||||
ldx #.lobyte(returnrun)
|
||||
sendmain: lda returnrun & $ff00,x
|
||||
DRIVESENDBYTE 1541, SENDVAL41
|
||||
inx
|
||||
bne sendmain
|
||||
inc sendmain + 2
|
||||
dec numpages41
|
||||
bne sendmain
|
||||
|
||||
lda #ATNA_OUT | CLK_OUT | DATA_OUT
|
||||
sta (V1B41,x); VIA1_PRB
|
||||
|
||||
lda #OPC_RTS
|
||||
sta getbyterts41
|
||||
|
||||
ldx #RESTOREMAIN41
|
||||
: lda .lobyte($0100 - RESTOREMAIN41),x
|
||||
ldy payldpre41 - $0100,x
|
||||
sty .lobyte($0100 - RESTOREMAIN41),x
|
||||
sta $00,x; buffer low end of zeropage at high end of zeropage
|
||||
inx
|
||||
bne :-
|
||||
|
||||
lda #ATNA_OUT
|
||||
sta ($03,x); VIA1_PRB
|
||||
|
||||
ldy VIA1_PRB
|
||||
.byte OPC_JMP_ABS, 0; jmp $0000
|
||||
|
||||
numpages41: .byte 7
|
||||
|
||||
CUSTOMPARAM41 = $fa
|
||||
|
||||
restorloop: sta (.lobyte(CUSTOMPARAM41 + 2),x); x = 0
|
||||
inc .lobyte(CUSTOMPARAM41 + 2)
|
||||
bne :+
|
||||
inc .lobyte(CUSTOMPARAM41 + 3)
|
||||
: inc .lobyte(CUSTOMPARAM41 + 4)
|
||||
bne restorloop + 3 - (custmstore - customloop)
|
||||
inc .lobyte(CUSTOMPARAM41 + 5)
|
||||
bne restorloop + 3 - (custmstore - customloop)
|
||||
.byte OPC_JMP_ABS
|
||||
.word $0200 - RETURNSIZE41; entry
|
||||
.word $0200 - RETURNSIZE41; to
|
||||
.word $10000 - ($0600 + RETURNSIZE41); length
|
||||
restrloope:
|
||||
|
||||
UPLOADOFFS = custmstore - (customloop + 3)
|
||||
|
||||
; executed at $0000
|
||||
customloop: DRIVEGETBYTE 1541, getbyte
|
||||
custmstore: sta (.lobyte(UPLOADOFFS + 19),x); x = 0
|
||||
inc .lobyte(UPLOADOFFS + 19)
|
||||
bne :+
|
||||
inc .lobyte(UPLOADOFFS + 20)
|
||||
: inc .lobyte(UPLOADOFFS + 21)
|
||||
bne customloop + 3
|
||||
inc .lobyte(UPLOADOFFS + 22)
|
||||
bne customloop + 3
|
||||
.byte OPC_JMP_ABS
|
||||
|
||||
.endscope
|
||||
|
||||
payldprm41: .word 0; entry
|
||||
.word 0; to
|
||||
.word 0; -length
|
||||
payldpre41:
|
||||
|
||||
return:
|
||||
.org $01e0
|
||||
|
||||
returnrun: ldx #<topofstack41
|
||||
lda #$18 ; ATNA_OUT | CLK_OUT
|
||||
sta (<(V1B41 - topofstack41),x); $1800
|
||||
txs
|
||||
ldx #21 - 1
|
||||
: lda SECTORLINKTABLE41,x
|
||||
sta RESTORELOOP41,x
|
||||
dex
|
||||
bpl :-
|
||||
lda (<(V2B41 - $ff),x); $1c00
|
||||
and #$08 ; BUSY_LED
|
||||
beq :+
|
||||
lda #$ff
|
||||
: sta LEDSTATE41
|
||||
jsr initlink41
|
||||
jmp idleloop41
|
||||
|
||||
.assert * = $0200, error, "***** 1541 return code at wrong position. *****"
|
||||
|
||||
.org * - (returnrun - return)
|
||||
returnend:
|
||||
|
||||
.assert * = $0200, error, "***** 1541 custom swap code at wrong position. *****"
|
||||
|
||||
RETURNSIZE41 = returnend - return
|
||||
|
||||
.reloc
|
||||
custm41end:
|
||||
|
||||
.if ONLY_1541_AND_COMPATIBLE = 0
|
||||
|
||||
drvcode71: .word 0; entry, not used here
|
||||
.word trmplrun71; to
|
||||
.word custom71end - trampoln71; length
|
||||
.word trampoln71; from
|
||||
|
||||
.word $0700 + RETURNSIZE71; buffer size
|
||||
bufmain71: .word 0; buffer
|
||||
|
||||
trampoln71:
|
||||
.org $0700; = BLOCKBUFFER71
|
||||
|
||||
RETURNSIZE71 = 34
|
||||
|
||||
trmplrun71: .scope custom71
|
||||
|
||||
.include "via.inc"
|
||||
|
||||
lda #$18 ; ATNA_OUT | CLK_OUT
|
||||
sta $1800; VIA1_PRB
|
||||
ldx #$ff
|
||||
lda $1c00; VIA2_PRB
|
||||
and #$08 ; BUSY_LED
|
||||
beq :+
|
||||
txa
|
||||
: sta LEDSTATE71
|
||||
stx <CLEARSECTORLINKTABLE71
|
||||
ldx #<topofstack71
|
||||
txs
|
||||
jsr initlink71
|
||||
: lda $1800; VIA1_PRB
|
||||
lsr
|
||||
bcc :-
|
||||
jmp idleloop71
|
||||
|
||||
sei
|
||||
lda #ATNA_OUT | CLK_OUT | DATA_OUT
|
||||
sta VIA1_PRB
|
||||
|
||||
; move receive routine for buffered loader code
|
||||
ldx #0
|
||||
: lda restorloop,x
|
||||
sta FILENAME71,x
|
||||
inx
|
||||
cpx #restrloope - restorloop
|
||||
bne :-
|
||||
|
||||
lda #ATNA_OUT
|
||||
sta VIA1_PRB
|
||||
lda #$05; CLK_IN | DATA_IN
|
||||
: and VIA1_PRB
|
||||
bne :-
|
||||
|
||||
SENDVAL71 = SECTORLINKTABLE71
|
||||
|
||||
; send loader code at $0000-$0700 plus return-to-loader code
|
||||
ldx #256 - RETURNSIZE71
|
||||
sendcode71: lda $ff00 + RETURNSIZE71,x
|
||||
DRIVESENDBYTE 1571, SENDVAL71
|
||||
inx
|
||||
bne :+
|
||||
inc sendcode71 + 2
|
||||
: inc count
|
||||
bne sendcode71
|
||||
inc count + 1
|
||||
bmi sendcode71
|
||||
|
||||
lda #ATNA_OUT | CLK_OUT | DATA_OUT
|
||||
sta VIA1_PRB
|
||||
|
||||
CUSTOMZPBUFFSIZE71 = payldpre71 - (customloop + 3)
|
||||
.export CUSTOMZPBUFFSIZE71
|
||||
ldx #CUSTOMZPBUFFSIZE71
|
||||
: lda customloop + 3 - 1,x
|
||||
ldy .lobyte($00 - 1),x
|
||||
sty .lobyte(CUSTOMZPBUFFER71 - 1),x
|
||||
sta .lobyte($00 - 1),x
|
||||
dex
|
||||
bne :-
|
||||
|
||||
lda #ATNA_OUT
|
||||
sta VIA1_PRB
|
||||
|
||||
ldy VIA1_PRB
|
||||
.byte OPC_JMP_ABS
|
||||
|
||||
count: .word $10000 - ($0700 + RETURNSIZE71)
|
||||
|
||||
CUSTOMPARAM71 = $5a
|
||||
|
||||
restorloop: DRIVEGETBYTE 1571, getbyterestore
|
||||
sta (.lobyte(CUSTOMPARAM71 + 2),x); x = 0
|
||||
inc .lobyte(CUSTOMPARAM71 + 2)
|
||||
bne :+
|
||||
inc .lobyte(CUSTOMPARAM71 + 3)
|
||||
: inc .lobyte(CUSTOMPARAM71 + 4)
|
||||
bne restorloop + 3
|
||||
inc .lobyte(CUSTOMPARAM71 + 5)
|
||||
bne restorloop + 3
|
||||
.byte OPC_JMP_ABS
|
||||
.word $0700; entry
|
||||
.word $0100; to
|
||||
.word $10000 - ($0600 + RETURNSIZE71); length
|
||||
restrloope:
|
||||
|
||||
UPLOADOFFS = getbytrt71 - (customloop + 3)
|
||||
|
||||
; executed at $0000
|
||||
customloop: DRIVEGETBYTE 1571, getbytecmp
|
||||
getbytrt71: sta (.lobyte(UPLOADOFFS + 19),x); x = 0
|
||||
inc .lobyte(UPLOADOFFS + 19)
|
||||
bne :+
|
||||
inc .lobyte(UPLOADOFFS + 20)
|
||||
: inc .lobyte(UPLOADOFFS + 21)
|
||||
bne customloop + 3
|
||||
inc .lobyte(UPLOADOFFS + 22)
|
||||
bne customloop + 3
|
||||
.byte OPC_JMP_ABS
|
||||
|
||||
.endscope
|
||||
|
||||
payldprm71: .word 0; entry
|
||||
.word 0; to
|
||||
.word 0; -length
|
||||
payldpre71:
|
||||
|
||||
.assert (* - trmplrun71) <= CUSTOMUPLOADSIZE71, error, "***** 1571 custom upload code too large. *****"
|
||||
.assert (* - trmplrun71) >= CUSTOMUPLOADSIZE71, error, "***** 1571 custom upload code too small. *****"
|
||||
|
||||
.reloc
|
||||
custom71end:
|
||||
|
||||
drvcode81: .word trampoln81; entry
|
||||
.word trampoln81; to
|
||||
.word custom81end - custom81; length
|
||||
.word custom81; from
|
||||
|
||||
.word DRVCODEND81 - $0300; buffer size
|
||||
bufmain81: .word 0; buffer
|
||||
|
||||
custom81:
|
||||
.org $0b00; = BLOCKBUFFER81
|
||||
|
||||
trampoln81: lda #payldpre81 - payldprm81 - 1; = $05 = CLK_IN | DATA_IN
|
||||
tax
|
||||
: ldy payldprm81,x
|
||||
sty CUSTOMPARAM81,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
;lda #CLK_IN | DATA_IN
|
||||
: bit CIA_PRB
|
||||
bne :-
|
||||
|
||||
SENDVAL81 = CUSTOMPARAM81 + 6
|
||||
|
||||
; send loader code at $0300
|
||||
ldx #0
|
||||
sendcode81: lda a:$0300 & $ff00,x
|
||||
DRIVESENDBYTE 1581, SENDVAL81
|
||||
inx
|
||||
bne :+
|
||||
inc sendcode81 + 2
|
||||
: cpx #.lobyte(DRVCODEND81)
|
||||
bne sendcode81
|
||||
lda sendcode81 + 2
|
||||
cmp #.hibyte(DRVCODEND81)
|
||||
bne sendcode81
|
||||
|
||||
ldx #0
|
||||
stx CIA_PRB
|
||||
|
||||
jmp CUSTOMRECEIVE81
|
||||
|
||||
payldprm81: .word 0; entry
|
||||
.word 0; to
|
||||
.word 0; -length
|
||||
payldpre81:
|
||||
.reloc
|
||||
custom81end:
|
||||
|
||||
.endif; !ONLY_1541_AND_COMPATIBLE
|
||||
193
loader/src/decompress/b2decomp.s
Executable file
193
loader/src/decompress/b2decomp.s
Executable file
|
|
@ -0,0 +1,193 @@
|
|||
; ByteBoozer Decruncher /HCL May.2003
|
||||
; B2 Decruncher December 2014
|
||||
; with slight modifications by Krill
|
||||
|
||||
decompress = Decrunch
|
||||
decompsrc = Get1+1
|
||||
|
||||
.FEATURE labels_without_colons, leading_dot_in_identifiers
|
||||
|
||||
;Variables.. #Bytes
|
||||
zp_base = DECOMPVARS ; -
|
||||
bits = zp_base ;1
|
||||
|
||||
put = decdestlo
|
||||
|
||||
|
||||
.macro .GetNextBit
|
||||
.local DgEnd
|
||||
asl bits
|
||||
bne DgEnd
|
||||
jsr GetNewBits
|
||||
DgEnd
|
||||
.endmacro
|
||||
|
||||
.macro .GetLen
|
||||
.local GlEnd
|
||||
.local GlLoop
|
||||
lda #1
|
||||
GlLoop
|
||||
.GetNextBit
|
||||
bcc GlEnd
|
||||
.GetNextBit
|
||||
rol
|
||||
bpl GlLoop
|
||||
GlEnd
|
||||
.endmacro
|
||||
|
||||
Decrunch
|
||||
jsr Gnb
|
||||
lda loadaddrhi
|
||||
sta Get2+2
|
||||
sta Get3+2
|
||||
ldx loadaddrlo
|
||||
jsr GetNewBits
|
||||
tya
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
adc loadaddroffslo
|
||||
php
|
||||
.endif
|
||||
storedadrl:
|
||||
sta put
|
||||
jsr GetNewBits
|
||||
tya
|
||||
.if LOADCOMPD_TO
|
||||
plp
|
||||
adc loadaddroffshi
|
||||
.endif
|
||||
storedadrh:
|
||||
sta put + 1
|
||||
lda #$80
|
||||
sta bits
|
||||
|
||||
DLoop
|
||||
POLLBLOCK
|
||||
|
||||
.GetNextBit
|
||||
bcs Match
|
||||
Literal
|
||||
; Literal run.. get length.
|
||||
.GetLen
|
||||
sta LLen+1
|
||||
|
||||
ldy #0
|
||||
LLoop
|
||||
Get3 lda $ff00,x
|
||||
inx
|
||||
bne *+5
|
||||
jsr GnbInc
|
||||
sta (put),y
|
||||
iny
|
||||
LLen cpy #0
|
||||
bne LLoop
|
||||
|
||||
clc
|
||||
tya
|
||||
adc put
|
||||
sta put
|
||||
bcc *+4
|
||||
inc put+1
|
||||
|
||||
iny
|
||||
beq DLoop
|
||||
|
||||
; Has to continue with a match..
|
||||
|
||||
Match
|
||||
; Match.. get length.
|
||||
.GetLen
|
||||
sta MLen+1
|
||||
|
||||
; Length 255 -> EOF
|
||||
cmp #$ff
|
||||
beq End
|
||||
|
||||
; Get num bits
|
||||
cmp #2
|
||||
lda #0
|
||||
rol
|
||||
.GetNextBit
|
||||
rol
|
||||
.GetNextBit
|
||||
rol
|
||||
tay
|
||||
lda Tab,y
|
||||
beq MByte
|
||||
|
||||
; Get bits < 8
|
||||
MLoop1 .GetNextBit
|
||||
rol
|
||||
bcs MLoop1
|
||||
bmi MShort
|
||||
MByte
|
||||
; Get byte
|
||||
eor #$ff
|
||||
tay
|
||||
Get2 lda $ff00,x
|
||||
inx
|
||||
bne MLong
|
||||
jsr GnbInc
|
||||
jmp MLong
|
||||
MShort
|
||||
ldy #$ff
|
||||
MLong
|
||||
;clc
|
||||
adc put
|
||||
sta MLda+1
|
||||
tya
|
||||
adc put+1
|
||||
sta MLda+2
|
||||
|
||||
ldy #$ff
|
||||
MLoop2 iny
|
||||
MLda lda $b00b,y
|
||||
sta (put),y
|
||||
MLen cpy #0
|
||||
bne MLoop2
|
||||
|
||||
;sec
|
||||
tya
|
||||
adc put
|
||||
sta put
|
||||
bcc *+4
|
||||
inc put+1
|
||||
|
||||
jmp DLoop
|
||||
|
||||
GetNewBits
|
||||
Get1 ldy $ff00,x
|
||||
sty bits
|
||||
rol bits
|
||||
inx
|
||||
beq GnbInc
|
||||
End rts
|
||||
|
||||
GnbInc
|
||||
inc Get1+2
|
||||
inc Get2+2
|
||||
inc Get3+2
|
||||
Gnb
|
||||
php
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
GETBLOCK Get1+2
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
ldx #0
|
||||
plp
|
||||
rts
|
||||
|
||||
Tab
|
||||
; Short offsets
|
||||
.byte %11011111 ; 3
|
||||
.byte %11111011 ; 6
|
||||
.byte %00000000 ; 8
|
||||
.byte %10000000 ; 10
|
||||
; Long offsets
|
||||
.byte %11101111 ; 4
|
||||
.byte %11111101 ; 7
|
||||
.byte %10000000 ; 10
|
||||
.byte %11110000 ; 13
|
||||
266
loader/src/decompress/bitnaxdecomp.s
Executable file
266
loader/src/decompress/bitnaxdecomp.s
Executable file
|
|
@ -0,0 +1,266 @@
|
|||
|
||||
decompsrc = bitfire_lz_sector_ptr1
|
||||
|
||||
.if MEM_DECOMP_TO_API
|
||||
; cannot copy remaining uncompressed blob of unknown size
|
||||
.error "***** MEM_DECOMP_TO_API is not supported for BITNAX. Copy compressed data to original location, then use MEM_DECOMP_API to decompress in-place. *****"
|
||||
.endif
|
||||
|
||||
BITFIRE_DECOMP_ZERO_OVERLAP = 1
|
||||
|
||||
.FEATURE labels_without_colons, leading_dot_in_identifiers
|
||||
|
||||
.lz_bits = DECOMPVARS + 0
|
||||
.lz_dst = DECOMPVARS + 1
|
||||
.lz_end = DECOMPVARS + 3
|
||||
.lz_tmp = DECOMPVARS + 5
|
||||
|
||||
decompress:
|
||||
jsr .lz_next_page_
|
||||
lda loadaddrhi
|
||||
sta bitfire_lz_sector_ptr2 + 1
|
||||
ldx loadaddrlo
|
||||
.if BITFIRE_DECOMP_ZERO_OVERLAP
|
||||
ldy #$03; destination and end addresses
|
||||
.else
|
||||
ldy #$01; destination address
|
||||
.endif
|
||||
: lda (loadaddrlo),y
|
||||
sta .lz_dst,y
|
||||
inx
|
||||
bne :+
|
||||
jsr .lz_next_page
|
||||
: dey
|
||||
bpl :--
|
||||
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc .lz_dst
|
||||
sta .lz_dst
|
||||
lda loadaddroffshi
|
||||
adc .lz_dst+1
|
||||
sta .lz_dst+1
|
||||
.if BITFIRE_DECOMP_ZERO_OVERLAP
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc .lz_end
|
||||
sta .lz_end
|
||||
lda loadaddroffshi
|
||||
adc .lz_end+1
|
||||
sta .lz_end+1
|
||||
.endif
|
||||
.endif
|
||||
sec
|
||||
|
||||
.lz_type_refill
|
||||
jsr .lz_refill_bits ;refill bit buffer .lz_bits
|
||||
|
||||
;******** Start the next match/literal run ********
|
||||
.lz_type_check
|
||||
bcc .lz_do_match
|
||||
beq .lz_type_refill ;we will fall through on entry
|
||||
|
||||
;******** Process literal run ********
|
||||
|
||||
lda #$00
|
||||
:
|
||||
rol ;-> a = $01 after first round
|
||||
asl .lz_bits
|
||||
bne *+5
|
||||
jsr .lz_refill_bits ;kills y
|
||||
bcc .lz_lrun_gotten
|
||||
|
||||
asl .lz_bits
|
||||
bne :-
|
||||
jsr .lz_refill_bits
|
||||
bne :-
|
||||
|
||||
.lz_lrun_gotten
|
||||
sta .lz_lcopy_len ;Store LSB of run-length
|
||||
ldy #$00
|
||||
.lz_lcopy
|
||||
bitfire_lz_sector_ptr2 = * + 1 ;Copy the literal data, forward or overlap is getting a pain in the ass.
|
||||
lda $ff00,x
|
||||
sta (.lz_dst),y
|
||||
inx
|
||||
bne :+
|
||||
clc
|
||||
jsr .lz_next_page
|
||||
:
|
||||
iny
|
||||
.lz_lcopy_len = * + 1
|
||||
cpy #$00
|
||||
bne .lz_lcopy
|
||||
|
||||
tya
|
||||
;.if LOAD_VIA_KERNAL_FALLBACK | (LOAD_UNDER_D000_DFFF & (PLATFORM <> diskio::platform::COMMODORE_16))
|
||||
bne *+5
|
||||
jmp .lz_maximum ;maximum literal run, bump sector pointers and so on and force new type bit
|
||||
;.else
|
||||
; beq .lz_maximum ;maximum literal run, bump sector pointers and so on and force new type bit
|
||||
;.endif
|
||||
;XXX TODO can we reuse the same code? In one case continue with match, in other case redecide
|
||||
clc
|
||||
adc .lz_dst
|
||||
sta .lz_dst
|
||||
bcc *+4
|
||||
inc .lz_dst+1
|
||||
|
||||
POLLBLOCK
|
||||
;no need for a type bit, after each literal a match follows, except for maximum runlength literals
|
||||
|
||||
;******** Process match ********
|
||||
|
||||
.lz_do_match
|
||||
lda #$01 ;this could be made shorter by using the last bitfetch of the upcoming loop and restoring the carry again by a cmp #$02. Saves bytes, but makes things slower, as eof check is also done with all short matches then
|
||||
|
||||
asl .lz_bits ;first length bit (where a one identifies
|
||||
bne *+5 ;a two-byte match)
|
||||
jsr .lz_refill_bits
|
||||
bcc .lz_get_offs ;all done, length is 2, skip further bitfetches (and eof check)
|
||||
:
|
||||
asl .lz_bits
|
||||
bne *+5
|
||||
jsr .lz_refill_bits
|
||||
rol
|
||||
|
||||
asl .lz_bits
|
||||
bne *+5
|
||||
jsr .lz_refill_bits
|
||||
bcc :-
|
||||
.lz_got_len
|
||||
tay ;XXX TODO could this be placed elsewhere to make the tay obsolete?
|
||||
beq .lz_end_of_file ;A 257-byte (=>$00) run serves as a sentinel, but not with zero-overlap, except when depacking from a non inplace address, then it is still appended
|
||||
.lz_get_offs
|
||||
sta .lz_mcopy_len ;store length at final destination
|
||||
|
||||
lda #%11000000 ;fetch 2 more prefix bits
|
||||
rol ;previous bit is still in carry \o/
|
||||
:
|
||||
asl .lz_bits
|
||||
bne *+5
|
||||
jsr .lz_refill_bits
|
||||
rol
|
||||
bcs :-
|
||||
|
||||
beq .lz_8_and_more ;0 + 8 bits to fetch, branch out before table lookup to save a few cycles and one byte in the table, also save complexity on the bitfetcher
|
||||
tay
|
||||
lda .lz_lentab,y
|
||||
: ;same as above
|
||||
asl .lz_bits ;XXX same code as above, so annoying :-(
|
||||
bne *+5
|
||||
jsr .lz_refill_bits
|
||||
rol
|
||||
bcs :-
|
||||
|
||||
bmi .lz_less_than_8 ;either 3,4,6 or 7 bits fetched -> highbyte will be $ff
|
||||
.lz_8_and_more
|
||||
jsr .lz_refill_bits
|
||||
eor #$ff ;5 of 13, 2 of 10, 0 of 8 bits fetched as highbyte, lowbyte still to be fetched
|
||||
sta .lz_tmp ;XXX this is a pain in the arse that A and Y need to be swapped :-(
|
||||
tya
|
||||
ldy .lz_tmp
|
||||
SKIPWORD
|
||||
.lz_less_than_8
|
||||
ldy #$ff ;XXX TODO silly, y is set twice in short case
|
||||
adc .lz_dst ;subtract offset from lz_dst
|
||||
sta .lz_m+1
|
||||
tya ;hibyte
|
||||
adc .lz_dst+1
|
||||
sta .lz_m+2
|
||||
|
||||
ldy #$ff ;The copy loop. This needs to be run
|
||||
;forwards since RLE-style matches can overlap the destination
|
||||
.lz_mcopy
|
||||
iny
|
||||
.lz_m lda $face,y ;copy one byte
|
||||
sta (.lz_dst),y
|
||||
.lz_mcopy_len = * + 1
|
||||
cpy #$ff
|
||||
bne .lz_mcopy
|
||||
|
||||
tya ;advance destination pointer
|
||||
; sec ;XXX TODO carry set = type check needed, cleared (literal) = match follows anyway
|
||||
adc .lz_dst
|
||||
sta .lz_dst
|
||||
|
||||
.if BITFIRE_DECOMP_ZERO_OVERLAP = 0
|
||||
.lz_skip_poll bcc :+
|
||||
.lz_maximum inc .lz_dst+1 ;this is also used by maximum length
|
||||
bcs .lz_skip_end
|
||||
:
|
||||
.else
|
||||
bcc :+ ;proceed to check
|
||||
.lz_maximum
|
||||
inc .lz_dst+1 ;advance hi byte
|
||||
; lda .lz_dst ;if entering via .lz_maximum, a = 0, so we would pass the following check only if the endadress is @ $xx00
|
||||
: ;if so, the endaddress can't be $xx00 and the highbyte check will fail, as we just successfully wrote a literal with type bit, so the end address must be greater then the current lz_dst, as either another literal or match must follow. Can you still follow me?! :-D
|
||||
eor .lz_end ;check end address
|
||||
.lz_skip_poll beq .lz_check_end ;all okay, poll for a new block
|
||||
|
||||
.endif ; BITFIRE_DECOMP_ZERO_OVERLAP
|
||||
|
||||
POLLBLOCK
|
||||
|
||||
.lz_skip_end
|
||||
;literals needing an explicit type bit
|
||||
asl .lz_bits ;fetch next type bit
|
||||
jmp .lz_type_check
|
||||
|
||||
.if BITFIRE_DECOMP_ZERO_OVERLAP
|
||||
|
||||
.lz_check_end
|
||||
lda .lz_dst+1 ;check highbyte
|
||||
eor .lz_end+1
|
||||
bne .lz_skip_end ;skip poll, so that only one branch needs to be manipulated
|
||||
;sta .barrier ;clear barrier and force to load until EOF, XXX does not work, but will at least force one additional block before leaving as barrier will be set again upon next block being fetched. Will overlap be > than 2 blocks? most likely not? CRAP, tony taught me that there is /o\
|
||||
;lda #$ff
|
||||
;sta bitfire_load_addr_hi ;needed if the barrier method will not work out, plain jump to poll loop will fail on stand alone depack?
|
||||
;jmp .lz_next_page ;load any remaining literal blob if there, or exit with rts in case of plain decomp (rts there instead of php). So we are forced until either the sector_ptr reaches $00xx or EOF happens, so nothing can go wrong
|
||||
|
||||
; fetching any remaining final literals uncompressed blob is performed by the caller (loadcompd in resident.s)
|
||||
.endif ; BITFIRE_DECOMP_ZERO_OVERLAP
|
||||
|
||||
.lz_end_of_file
|
||||
rts
|
||||
|
||||
.lz_refill_bits
|
||||
bitfire_lz_sector_ptr1 = * + 1
|
||||
bitfire_load_addr_hi = * + 2
|
||||
ldy $ff00,x
|
||||
inx
|
||||
bne .lz_same_page
|
||||
|
||||
.lz_next_page
|
||||
inc bitfire_load_addr_hi
|
||||
inc bitfire_lz_sector_ptr2 + 1
|
||||
.lz_next_page_
|
||||
php
|
||||
pha
|
||||
sty .lz_tmp
|
||||
GETBLOCK bitfire_load_addr_hi
|
||||
ldx #0
|
||||
ldy .lz_tmp
|
||||
pla
|
||||
plp
|
||||
|
||||
.lz_same_page
|
||||
;store bits? happens on all calls, except when a whole literal is fetched
|
||||
bcc :+ ;only store lz_bits if carry is set (in all cases, except when literal is fetched for offset)
|
||||
sty .lz_bits
|
||||
rol .lz_bits
|
||||
: rts
|
||||
|
||||
.lz_lentab = * - 1
|
||||
;short offset init values
|
||||
;.byte %00000000 ;2
|
||||
.byte %11011111 ;0
|
||||
.byte %11111011 ;1
|
||||
.byte %10000000 ;3
|
||||
|
||||
;long offset init values
|
||||
.byte %11101111 ;offset 0
|
||||
.byte %11111101 ;offset 1
|
||||
.byte %10000000 ;offset 2
|
||||
.byte %11110000 ;offset 3
|
||||
305
loader/src/decompress/doynaxdecomp.s
Executable file
305
loader/src/decompress/doynaxdecomp.s
Executable file
|
|
@ -0,0 +1,305 @@
|
|||
|
||||
decompsrc = lz_sector_ptr1
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
;Regular version of the Lempel-Ziv decompressor
|
||||
;-------------------------------------------------------------------------------
|
||||
lz_dst = decdestlo ;Decompression destination pointer.
|
||||
;Initialize this to whatever address
|
||||
;you want to decompress to
|
||||
|
||||
lz_bits = DECOMPVARS + $00 ;Shift register. Initialized to $80
|
||||
;for a new file
|
||||
|
||||
lz_scratch = DECOMPVARS + $01 ;Temporary zeropage storage
|
||||
|
||||
lz_ybuffer = DECOMPVARS + $02 ;Temporary register storage when fetching sector
|
||||
|
||||
lz_sector = $ff00 ;The one-page buffer from which the
|
||||
;compressed data is actually read,
|
||||
;and which gets refilled by
|
||||
;lz_fetch_sector.
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
;This is the user's hook to replenish the sector buffer with some new bytes.
|
||||
;
|
||||
;A and Y are expected to be preserved while carry must remain set on exit.
|
||||
;X should point to the first byte of the new data, e.g. zero for a full 256-byte
|
||||
;page of data or two to skip past the sector and track links.
|
||||
;
|
||||
;When fetching from a larger in-memory array rather than a single sector buffer
|
||||
;the lz_sector_ptr1..3 pointers will need to be patched up
|
||||
;-------------------------------------------------------------------------------
|
||||
lz_fetch_sector:
|
||||
inc lz_sector_ptr1 + 1
|
||||
inc lz_sector_ptr2 + 1
|
||||
inc lz_sector_ptr3 + 1
|
||||
lz_fetch_sector_:
|
||||
pha
|
||||
sty lz_ybuffer
|
||||
GETBLOCK lz_sector_ptr1 + 1
|
||||
ldx #0
|
||||
ldy lz_ybuffer
|
||||
pla
|
||||
sec
|
||||
rts
|
||||
|
||||
decompress:
|
||||
jsr lz_fetch_sector_
|
||||
lda loadaddrhi
|
||||
sta lz_sector_ptr2 + 1
|
||||
sta lz_sector_ptr3 + 1
|
||||
ldx loadaddrlo
|
||||
|
||||
jsr _lz_refill_bits
|
||||
tya
|
||||
storedadrl:
|
||||
sta lz_dst + $00
|
||||
jsr _lz_refill_bits
|
||||
tya
|
||||
storedadrh:
|
||||
sta lz_dst + $01
|
||||
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc lz_dst + $00
|
||||
sta lz_dst + $00
|
||||
lda loadaddroffshi
|
||||
adc lz_dst + $01
|
||||
sta lz_dst + $01
|
||||
.endif
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
;This is the main lz_decrunch function which may be called to decompress an
|
||||
;entire file.
|
||||
;
|
||||
;On entry and exit the X register points to the next available byte in the
|
||||
;sector buffer, in ascending order from $00 to $ff.
|
||||
;This implies that the initial sector must have already been fetched, and that a
|
||||
;file ending with X wrapped to $00 will have needlessly fetched an extra sector
|
||||
;(which may be taken advantage of when decoding a contiguous set of files.)
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
;******** Start the next match/literal run ********
|
||||
|
||||
lz_decrunch: sec ;This is the main entry point. Forcibly
|
||||
_lz_type_refill:
|
||||
jsr _lz_refill_bits ;fill up the the bit buffer on entry
|
||||
bne _lz_type_cont ;(BRA)
|
||||
|
||||
;Wrap the high-byte of the destination pointer.
|
||||
_lz_mfinish: bcc *+4
|
||||
_lz_maximum: inc lz_dst+1 ;This is also used by maximum length
|
||||
;literals needing an explicit type bit
|
||||
|
||||
POLLBLOCK
|
||||
|
||||
;Literal or match to follow?
|
||||
asl lz_bits
|
||||
_lz_type_cont: bcc _lz_do_match
|
||||
beq lz_decrunch
|
||||
|
||||
|
||||
;******** Process literal run ********
|
||||
|
||||
lda #%00000000 ;Decode run length
|
||||
_lz_lrun_loop: rol
|
||||
asl lz_bits
|
||||
bcs _lz_lrun_test
|
||||
_lz_lrun_back: asl lz_bits
|
||||
bne _lz_lrun_loop
|
||||
|
||||
jsr _lz_refill_bits
|
||||
bne _lz_lrun_loop ;(BRA)
|
||||
|
||||
_lz_lrun_test: bne _lz_lrun_gotten
|
||||
jsr _lz_refill_bits
|
||||
bcc _lz_lrun_back
|
||||
|
||||
_lz_lrun_gotten:
|
||||
sta _lz_copy_cnt+1 ;Store LSB of run-length
|
||||
ldy #$00
|
||||
_lz_lcopy:
|
||||
lz_sector_ptr2 = *+1 ;Copy the literal data. Note the
|
||||
lda lz_sector,x
|
||||
inx
|
||||
bne *+5
|
||||
jsr lz_fetch_sector ;Grab a new sector for the literal loop
|
||||
sta (lz_dst),y
|
||||
iny
|
||||
_lz_copy_cnt: cpy #$00
|
||||
bne _lz_lcopy
|
||||
|
||||
;Time to advance the destination pointer.
|
||||
;Maximum run length literals exit here as a type-bit needs
|
||||
;to be fetched afterwards
|
||||
tya
|
||||
beq _lz_maximum
|
||||
clc
|
||||
adc lz_dst+0
|
||||
sta lz_dst+0
|
||||
bcc *+4
|
||||
inc lz_dst+1
|
||||
|
||||
POLLBLOCK
|
||||
|
||||
;One literal run following another only makes sense if the
|
||||
;first run is of maximum length and had to be split. As that
|
||||
;case has been taken care of we can safely omit the type bit
|
||||
;here
|
||||
|
||||
|
||||
;******** Process match ********
|
||||
|
||||
_lz_do_match: lda #%00100000 ;Determine offset length by a two-bit
|
||||
_lz_moff_range: asl lz_bits ;prefix combined with the first run
|
||||
bne *+5 ;length bit (where a one identifies
|
||||
jsr _lz_refill_bits ;a two-byte match).
|
||||
rol ;The rest of the length bits will
|
||||
bcc _lz_moff_range ;then follow *after* the offset data
|
||||
|
||||
tay
|
||||
lda _lz_moff_length,y
|
||||
beq _lz_moff_far
|
||||
|
||||
_lz_moff_loop: asl lz_bits ;Load partial offset byte
|
||||
bne *+9
|
||||
sty lz_scratch
|
||||
jsr _lz_refill_bits
|
||||
ldy lz_scratch
|
||||
|
||||
rol
|
||||
bcc _lz_moff_loop
|
||||
|
||||
bmi _lz_moff_near
|
||||
|
||||
_lz_moff_far: sta lz_scratch ;Save the bits we just read as the
|
||||
;high-byte
|
||||
|
||||
lz_sector_ptr3 = *+1
|
||||
lda lz_sector,x ;For large offsets we can load the
|
||||
inx ;low-byte straight from the stream
|
||||
bne *+5 ;without going throught the shift
|
||||
jsr lz_fetch_sector ;register
|
||||
|
||||
; sec
|
||||
adc _lz_moff_adjust_lo,y
|
||||
bcs _lz_moff_pageok
|
||||
dec lz_scratch
|
||||
sec
|
||||
_lz_moff_pageok:
|
||||
adc lz_dst+0
|
||||
sta _lz_match+0
|
||||
|
||||
lda lz_scratch
|
||||
adc _lz_moff_adjust_hi,y
|
||||
sec
|
||||
bcs _lz_moff_join ;(BRA)
|
||||
|
||||
_lz_moff_near:
|
||||
; sec ;Special case handling of <8 bit offsets.
|
||||
adc _lz_moff_adjust_lo,y;We may can safely ignore the MSB from
|
||||
; sec ;the base adjustment table as the
|
||||
adc lz_dst+0 ;maximum base (for a 4/5/6/7 bit
|
||||
sta _lz_match+0 ;length sequence) is 113
|
||||
lda #$ff
|
||||
_lz_moff_join: adc lz_dst+1
|
||||
sta _lz_match+1
|
||||
|
||||
cpy #$04 ;Get any remaning run length bits
|
||||
lda #%00000001
|
||||
bcs _lz_mrun_gotten
|
||||
|
||||
_lz_mrun_loop: asl lz_bits
|
||||
bne *+5
|
||||
jsr _lz_refill_bits
|
||||
rol
|
||||
asl lz_bits
|
||||
bcc _lz_mrun_loop
|
||||
bne _lz_mrun_gotten
|
||||
jsr _lz_refill_bits
|
||||
bcc _lz_mrun_loop
|
||||
|
||||
_lz_mrun_gotten:
|
||||
tay ;A 257-byte (=>$00) run serves as a
|
||||
beq _lz_end_of_file ;sentinel
|
||||
|
||||
sta _lz_mcopy_len
|
||||
|
||||
ldy #$ff ;The copy loop. This needs to be run
|
||||
_lz_mcopy: iny ;forwards since RLE-style matches can
|
||||
_lz_match = *+1 ;overlap the destination
|
||||
lda $ffff,y
|
||||
sta (lz_dst),y
|
||||
_lz_mcopy_len = *+1
|
||||
cpy #$ff
|
||||
bne _lz_mcopy
|
||||
|
||||
tya ;Advance destination pointer
|
||||
; sec
|
||||
adc lz_dst+0
|
||||
sta lz_dst+0
|
||||
jmp _lz_mfinish
|
||||
|
||||
|
||||
;******** Fetch some more bits to work with ********
|
||||
|
||||
lz_sector_ptr1 = *+1
|
||||
_lz_refill_bits:
|
||||
ldy lz_sector,x
|
||||
sty lz_bits
|
||||
inx
|
||||
bne *+5
|
||||
jsr lz_fetch_sector
|
||||
; sec
|
||||
rol lz_bits
|
||||
_lz_end_of_file:
|
||||
rts
|
||||
|
||||
;******** Offset coding tables ********
|
||||
|
||||
;This length table is a bit funky. The idea here is to use the
|
||||
;value as the initial value of the shift register instead of
|
||||
;keeping a separate counter.
|
||||
;In other words we iterate until the leading one is shifted out.
|
||||
;Then afterwards the bit just below it (our new sign bit) is set
|
||||
;if the offset is shorter than 8-bits, and conversely it's
|
||||
;cleared if we need to fetch a separate low-byte
|
||||
;as well.
|
||||
;The fact that the sign bit is cleared as a flag is compensated
|
||||
;for in the lz_moff_adjust_hi table
|
||||
|
||||
_lz_moff_length:
|
||||
;Long (>2 byte matches)
|
||||
.byte %00011111 ;4 bits
|
||||
.byte %00000011 ;7 bits
|
||||
.byte %01011111 ;10 bits
|
||||
.byte %00001011 ;13 bits
|
||||
;Short (2 byte matches)
|
||||
.byte %01011111 ;10 bits
|
||||
.byte %00000000 ;8 bits
|
||||
.byte %00000111 ;6 bits
|
||||
.byte %00111111 ;3 bits
|
||||
_lz_moff_adjust_lo:
|
||||
;Long (>2 byte matches)
|
||||
.byte %11111110 ;1-16
|
||||
.byte %11101110 ;17-144
|
||||
.byte %01101110 ;145-1168
|
||||
.byte %01101110 ;1169-9360
|
||||
;Short (2 byte matches)
|
||||
.byte %10110110 ;329-1352
|
||||
.byte %10110110 ;73-328
|
||||
.byte %11110110 ;9-72
|
||||
.byte %11111110 ;1-8
|
||||
_lz_moff_adjust_hi = *-2
|
||||
;Long (>2 byte matches)
|
||||
; .byte %11111111 ;1-16 (unreferenced)
|
||||
; .byte %11111111 ;17-144 (unreferenced)
|
||||
.byte %01111111 ;145-1168
|
||||
.byte %01111011 ;1169-9360
|
||||
;Short (2 byte matches)
|
||||
.byte %01111110 ;329-1352
|
||||
.byte %11111110 ;73-328
|
||||
; .byte %11111111 ;9-72 (unreferenced)
|
||||
; .byte %11111111 ;1-8 (unreferenced)
|
||||
611
loader/src/decompress/exodecomp.s
Executable file
611
loader/src/decompress/exodecomp.s
Executable file
|
|
@ -0,0 +1,611 @@
|
|||
; slightly modified by Krill/Plush for loader integration
|
||||
|
||||
;
|
||||
; Copyright (c) 2002 - 2020 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.
|
||||
;
|
||||
; -------------------------------------------------------------------
|
||||
; Known quirks:
|
||||
; Can't handle a sequence reference that ends at $ffff. It is left in
|
||||
; since it is a corner case and fixing it impacts negatively on
|
||||
; performance or backwards compatibility.
|
||||
; A simple way to work around this is to not decrunch to address $ffff.
|
||||
; -------------------------------------------------------------------
|
||||
; Controls if the shared get_bits routines should be inlined or not.
|
||||
;INLINE_GET_BITS=1
|
||||
.IFNDEF INLINE_GET_BITS
|
||||
INLINE_GET_BITS = 0
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; if literal sequences is not used (the data was crunched with the -c
|
||||
; flag) then the following line can be uncommented for shorter and.
|
||||
; slightly faster code.
|
||||
;LITERAL_SEQUENCES_NOT_USED = 1
|
||||
.IFNDEF LITERAL_SEQUENCES_NOT_USED
|
||||
LITERAL_SEQUENCES_NOT_USED = 0
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; if the sequence length is limited to 256 (the data was crunched with
|
||||
; the -M256 flag) then the following line can be uncommented for
|
||||
; shorter and slightly faster code.
|
||||
;MAX_SEQUENCE_LENGTH_256 = 1
|
||||
.IFNDEF MAX_SEQUENCE_LENGTH_256
|
||||
MAX_SEQUENCE_LENGTH_256 = 0
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; if the sequence length 3 has its own offset table (the data was
|
||||
; crunched with the -P+16 flag) then the following
|
||||
; line must be uncommented.
|
||||
;EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE = 1
|
||||
.IFNDEF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE
|
||||
EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE = 0
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; if sequence offsets are not reused (the data was crunched with the
|
||||
; -P-32 flag) then the following line must be uncommented. Uncommenting the
|
||||
; line will also result in shorter and slightly faster code.
|
||||
;DONT_REUSE_OFFSET = 1
|
||||
.IFNDEF DONT_REUSE_OFFSET
|
||||
DONT_REUSE_OFFSET = 0
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; if decrunching forwards then the following line must be uncommented.
|
||||
DECRUNCH_FORWARDS = 1
|
||||
.IFNDEF DECRUNCH_FORWARDS
|
||||
DECRUNCH_FORWARDS = 0
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; if split encoding is used (the data is crunched with the -E flag)
|
||||
; then the following line must be uncommented.
|
||||
;ENABLE_SPLIT_ENCODING = 1
|
||||
.IFNDEF ENABLE_SPLIT_ENCODING
|
||||
ENABLE_SPLIT_ENCODING = 0
|
||||
.ENDIF
|
||||
|
||||
; -------------------------------------------------------------------
|
||||
; The decruncher jsr:s to the get_crunched_byte address when it wants to
|
||||
; read a crunched byte into A. This subroutine has to preserve X and Y
|
||||
; register and must not modify the state of the carry nor the overflow flag.
|
||||
; -------------------------------------------------------------------
|
||||
;.import get_crunched_byte
|
||||
; -------------------------------------------------------------------
|
||||
; This function is the heart of the decruncher. (for non split crunched files)
|
||||
; 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.
|
||||
; -------------------------------------------------------------------
|
||||
;.export decrunch
|
||||
.IF ENABLE_SPLIT_ENCODING <> 0
|
||||
; -------------------------------------------------------------------
|
||||
; To decrunch files crunched with the split feature (-E) you can't use the
|
||||
; decrunch function. Instead you call the split_decrunch function. But you
|
||||
; can only do this if the decrunch table contains the encoding used by the
|
||||
; file you are decrunching. To generate the correct content for the decrunch
|
||||
; table call set the get_crunched_byte function to point to the encoding data
|
||||
; and then call the split_gentable function.
|
||||
; -------------------------------------------------------------------
|
||||
.export split_gentable
|
||||
.export split_decrunch
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; zero page addresses used
|
||||
; -------------------------------------------------------------------
|
||||
zp_len_lo = DECOMPVARS + 0; $9e
|
||||
zp_len_hi = DECOMPVARS + 1; $9f
|
||||
|
||||
zp_src_lo = DECOMPVARS + 2; $ae
|
||||
zp_src_hi = zp_src_lo + 1
|
||||
|
||||
zp_bits_hi = DECOMPVARS + 4; $a7
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
zp_ro_state = DECOMPVARS + 5; $a8
|
||||
.ENDIF
|
||||
|
||||
zp_bitbuf = DECOMPVARS + 6; $fd
|
||||
.if MEM_DECOMP_TO_API
|
||||
zp_dest_lo = decdestlo; zp_bitbuf + 1 ; dest addr lo
|
||||
zp_dest_hi = decdesthi; zp_bitbuf + 2 ; dest addr hi
|
||||
.else
|
||||
zp_dest_lo = zp_bitbuf + 1 ; dest addr lo
|
||||
zp_dest_hi = zp_bitbuf + 2 ; dest addr hi
|
||||
.endif
|
||||
|
||||
.IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE <> 0
|
||||
encoded_entries = 68
|
||||
.ELSE
|
||||
encoded_entries = 52
|
||||
.ENDIF
|
||||
|
||||
tabl_bi = decrunch_table
|
||||
tabl_lo = decrunch_table + encoded_entries
|
||||
tabl_hi = decrunch_table + encoded_entries * 2
|
||||
|
||||
decompress = decrunch
|
||||
|
||||
get_crunched_byte:
|
||||
php
|
||||
jsr getbyte
|
||||
plp
|
||||
rts
|
||||
|
||||
;; refill bits is always inlined
|
||||
.MACRO mac_refill_bits
|
||||
pha
|
||||
jsr get_crunched_byte
|
||||
rol
|
||||
sta zp_bitbuf
|
||||
pla
|
||||
.ENDMACRO
|
||||
|
||||
.MACRO mac_get_bits
|
||||
.IF INLINE_GET_BITS <> 0
|
||||
.SCOPE
|
||||
adc #$80 ; needs c=0, affects v
|
||||
asl
|
||||
bpl gb_skip
|
||||
gb_next:
|
||||
asl zp_bitbuf
|
||||
bne gb_ok
|
||||
mac_refill_bits
|
||||
gb_ok:
|
||||
rol
|
||||
bmi gb_next
|
||||
gb_skip:
|
||||
bvc skip
|
||||
gb_get_hi:
|
||||
sec
|
||||
sta zp_bits_hi
|
||||
jsr get_crunched_byte
|
||||
skip:
|
||||
.ENDSCOPE
|
||||
.ELSE
|
||||
jsr get_bits
|
||||
.ENDIF
|
||||
.ENDMACRO
|
||||
|
||||
.MACRO mac_init_zp
|
||||
;.SCOPE
|
||||
; -------------------------------------------------------------------
|
||||
; init zeropage and x reg. (8 bytes)
|
||||
;
|
||||
init_zp:
|
||||
.if MEM_DECOMP_TO_API
|
||||
jsr get_crunched_byte
|
||||
storedadrh:
|
||||
sta zp_dest_hi
|
||||
jsr get_crunched_byte
|
||||
storedadrl:
|
||||
sta zp_dest_lo
|
||||
jsr get_crunched_byte
|
||||
sta zp_bitbuf
|
||||
.else
|
||||
jsr get_crunched_byte
|
||||
sta zp_bitbuf - 1,x
|
||||
dex
|
||||
bne init_zp
|
||||
.endif
|
||||
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc zp_dest_lo
|
||||
sta zp_dest_lo
|
||||
lda loadaddroffshi
|
||||
adc zp_dest_hi
|
||||
sta zp_dest_hi
|
||||
.endif
|
||||
;.ENDSCOPE
|
||||
.ENDMACRO
|
||||
|
||||
.IF INLINE_GET_BITS = 0
|
||||
get_bits:
|
||||
adc #$80 ; needs c=0, affects v
|
||||
asl
|
||||
bpl gb_skip
|
||||
gb_next:
|
||||
asl zp_bitbuf
|
||||
bne gb_ok
|
||||
mac_refill_bits
|
||||
gb_ok:
|
||||
rol
|
||||
bmi gb_next
|
||||
gb_skip:
|
||||
bvs gb_get_hi
|
||||
rts
|
||||
gb_get_hi:
|
||||
sec
|
||||
sta zp_bits_hi
|
||||
jmp get_crunched_byte
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; 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 cleared (it almost always is, otherwise do a cld)
|
||||
decrunch:
|
||||
.IF ENABLE_SPLIT_ENCODING <> 0
|
||||
ldx #3
|
||||
jsr internal_gentable
|
||||
jmp normal_decrunch
|
||||
split_gentable:
|
||||
ldx #1
|
||||
internal_gentable:
|
||||
jsr split_init_zp
|
||||
.ELSE
|
||||
ldx #3
|
||||
mac_init_zp
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; calculate tables (64 bytes) + get_bits macro
|
||||
; x must be #0 when entering
|
||||
;
|
||||
ldy #0
|
||||
clc
|
||||
table_gen:
|
||||
tax
|
||||
tya
|
||||
and #$0f
|
||||
sta tabl_lo,y
|
||||
beq shortcut ; start a new sequence
|
||||
; -------------------------------------------------------------------
|
||||
txa
|
||||
adc tabl_lo - 1,y
|
||||
sta tabl_lo,y
|
||||
lda zp_len_hi
|
||||
adc tabl_hi - 1,y
|
||||
shortcut:
|
||||
sta tabl_hi,y
|
||||
; -------------------------------------------------------------------
|
||||
lda #$01
|
||||
sta <zp_len_hi
|
||||
lda #$78 ; %01111000
|
||||
mac_get_bits
|
||||
; -------------------------------------------------------------------
|
||||
lsr
|
||||
tax
|
||||
beq rolled
|
||||
php
|
||||
rolle:
|
||||
asl zp_len_hi
|
||||
sec
|
||||
ror
|
||||
dex
|
||||
bne rolle
|
||||
plp
|
||||
rolled:
|
||||
ror
|
||||
sta tabl_bi,y
|
||||
bmi no_fixup_lohi
|
||||
lda zp_len_hi
|
||||
stx zp_len_hi
|
||||
.BYTE $24
|
||||
no_fixup_lohi:
|
||||
txa
|
||||
; -------------------------------------------------------------------
|
||||
iny
|
||||
cpy #encoded_entries
|
||||
bne table_gen
|
||||
; -------------------------------------------------------------------
|
||||
.IF ENABLE_SPLIT_ENCODING <> 0
|
||||
rts
|
||||
split_decrunch:
|
||||
ldx #3
|
||||
jsr split_init_zp
|
||||
; X reg must be 0 here
|
||||
sec
|
||||
normal_decrunch:
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; prepare for main decruncher
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
ror zp_ro_state
|
||||
sec
|
||||
.ENDIF
|
||||
ldy zp_dest_lo
|
||||
stx zp_dest_lo
|
||||
stx zp_bits_hi
|
||||
; -------------------------------------------------------------------
|
||||
; copy one literal byte to destination (11 bytes)
|
||||
;
|
||||
literal_start1:
|
||||
.IF DECRUNCH_FORWARDS = 0
|
||||
tya
|
||||
bne no_hi_decr
|
||||
dec zp_dest_hi
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
dec zp_src_hi
|
||||
.ENDIF
|
||||
no_hi_decr:
|
||||
dey
|
||||
.ENDIF
|
||||
jsr get_crunched_byte
|
||||
sta (zp_dest_lo),y
|
||||
.IF DECRUNCH_FORWARDS <> 0
|
||||
iny
|
||||
bne skip_hi_incr
|
||||
inc zp_dest_hi
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
inc zp_src_hi
|
||||
.ENDIF
|
||||
skip_hi_incr:
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; fetch sequence length index (15 bytes)
|
||||
; x must be #0 when entering and contains the length index + 1
|
||||
; when exiting or 0 for literal byte
|
||||
next_round:
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
ror zp_ro_state
|
||||
.ENDIF
|
||||
dex
|
||||
lda zp_bitbuf
|
||||
no_literal1:
|
||||
asl
|
||||
bne nofetch8
|
||||
jsr get_crunched_byte
|
||||
rol
|
||||
nofetch8:
|
||||
inx
|
||||
bcc no_literal1
|
||||
sta zp_bitbuf
|
||||
; -------------------------------------------------------------------
|
||||
; check for literal byte (2 bytes)
|
||||
;
|
||||
beq literal_start1
|
||||
; -------------------------------------------------------------------
|
||||
; check for decrunch done and literal sequences (4 bytes)
|
||||
;
|
||||
cpx #$11
|
||||
.IF INLINE_GET_BITS <> 0
|
||||
bcc skip_jmp
|
||||
jmp exit_or_lit_seq
|
||||
skip_jmp:
|
||||
.ELSE
|
||||
bcs exit_or_lit_seq
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; calulate length of sequence (zp_len) (18(11) bytes) + get_bits macro
|
||||
;
|
||||
lda tabl_bi - 1,x
|
||||
mac_get_bits
|
||||
adc tabl_lo - 1,x ; we have now calculated zp_len_lo
|
||||
sta zp_len_lo
|
||||
.IF MAX_SEQUENCE_LENGTH_256 = 0
|
||||
lda zp_bits_hi
|
||||
adc tabl_hi - 1,x ; c = 0 after this.
|
||||
sta zp_len_hi
|
||||
; -------------------------------------------------------------------
|
||||
; here we decide what offset table to use (27(26) bytes) + get_bits_nc macro
|
||||
; z-flag reflects zp_len_hi here
|
||||
;
|
||||
ldx zp_len_lo
|
||||
.ELSE
|
||||
tax
|
||||
.ENDIF
|
||||
.IF MAX_SEQUENCE_LENGTH_256 = 0
|
||||
lda #0
|
||||
.ENDIF
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
; -------------------------------------------------------------------
|
||||
; here we decide to reuse latest offset or not (13(15) bytes)
|
||||
;
|
||||
bit <zp_ro_state
|
||||
bmi test_reuse
|
||||
no_reuse:
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; here we decide what offset table to use (17(15) bytes)
|
||||
;
|
||||
.IF MAX_SEQUENCE_LENGTH_256 = 0
|
||||
sta <zp_bits_hi
|
||||
.ENDIF
|
||||
lda #$e1
|
||||
.IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE <> 0
|
||||
cpx #$04
|
||||
.ELSE
|
||||
cpx #$03
|
||||
.ENDIF
|
||||
bcs gbnc2_next
|
||||
lda tabl_bit - 1,x
|
||||
gbnc2_next:
|
||||
asl zp_bitbuf
|
||||
bne gbnc2_ok
|
||||
tax
|
||||
jsr get_crunched_byte
|
||||
rol
|
||||
sta zp_bitbuf
|
||||
txa
|
||||
gbnc2_ok:
|
||||
rol
|
||||
bcs gbnc2_next
|
||||
tax
|
||||
; -------------------------------------------------------------------
|
||||
; calulate absolute offset (zp_src) (17 bytes) + get_bits macro
|
||||
;
|
||||
lda tabl_bi,x
|
||||
mac_get_bits
|
||||
.IF DECRUNCH_FORWARDS = 0
|
||||
adc tabl_lo,x
|
||||
sta zp_src_lo
|
||||
lda zp_bits_hi
|
||||
adc tabl_hi,x
|
||||
adc zp_dest_hi
|
||||
sta zp_src_hi
|
||||
.ELSE
|
||||
clc
|
||||
adc tabl_lo,x
|
||||
eor #$ff
|
||||
sta zp_src_lo
|
||||
lda zp_bits_hi
|
||||
adc tabl_hi,x
|
||||
eor #$ff
|
||||
adc zp_dest_hi
|
||||
sta zp_src_hi
|
||||
clc
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; prepare for copy loop (2 bytes)
|
||||
;
|
||||
ldx zp_len_lo
|
||||
; -------------------------------------------------------------------
|
||||
; main copy loop (30 bytes)
|
||||
;
|
||||
copy_next:
|
||||
.IF DECRUNCH_FORWARDS = 0
|
||||
tya
|
||||
bne copy_skip_hi
|
||||
dec zp_dest_hi
|
||||
dec zp_src_hi
|
||||
copy_skip_hi:
|
||||
dey
|
||||
.ENDIF
|
||||
.IF LITERAL_SEQUENCES_NOT_USED = 0
|
||||
bcs get_literal_byte
|
||||
.ENDIF
|
||||
lda (zp_src_lo),y
|
||||
literal_byte_gotten:
|
||||
sta (zp_dest_lo),y
|
||||
.IF DECRUNCH_FORWARDS <> 0
|
||||
iny
|
||||
bne copy_skip_hi
|
||||
inc zp_dest_hi
|
||||
inc zp_src_hi
|
||||
copy_skip_hi:
|
||||
.ENDIF
|
||||
dex
|
||||
bne copy_next
|
||||
.IF MAX_SEQUENCE_LENGTH_256 = 0
|
||||
lda zp_len_hi
|
||||
.IF INLINE_GET_BITS <> 0
|
||||
bne copy_next_hi
|
||||
.ENDIF
|
||||
.ENDIF
|
||||
stx zp_bits_hi
|
||||
.IF INLINE_GET_BITS = 0
|
||||
beq next_round
|
||||
.ELSE
|
||||
jmp next_round
|
||||
.ENDIF
|
||||
.IF MAX_SEQUENCE_LENGTH_256 = 0
|
||||
copy_next_hi:
|
||||
dec zp_len_hi
|
||||
jmp copy_next
|
||||
.ENDIF
|
||||
.IF DONT_REUSE_OFFSET = 0
|
||||
; -------------------------------------------------------------------
|
||||
; test for offset reuse (11 bytes)
|
||||
;
|
||||
test_reuse:
|
||||
bvs no_reuse
|
||||
.IF MAX_SEQUENCE_LENGTH_256 <> 0
|
||||
lda #$00 ; fetch one bit
|
||||
.ENDIF
|
||||
asl zp_bitbuf
|
||||
bne gbnc1_ok
|
||||
pha
|
||||
jsr get_crunched_byte
|
||||
rol
|
||||
sta zp_bitbuf
|
||||
pla
|
||||
gbnc1_ok:
|
||||
rol
|
||||
beq no_reuse ; bit == 0 => C=0, no reuse
|
||||
bne copy_next ; bit != 0 => C=0, reuse previous offset
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; exit or literal sequence handling (16(12) bytes)
|
||||
;
|
||||
exit_or_lit_seq:
|
||||
.IF LITERAL_SEQUENCES_NOT_USED = 0
|
||||
beq decr_exit
|
||||
jsr get_crunched_byte
|
||||
.IF MAX_SEQUENCE_LENGTH_256 = 0
|
||||
sta zp_len_hi
|
||||
.ENDIF
|
||||
jsr get_crunched_byte
|
||||
tax
|
||||
bcs copy_next
|
||||
decr_exit:
|
||||
.ENDIF
|
||||
rts
|
||||
.IF LITERAL_SEQUENCES_NOT_USED = 0
|
||||
get_literal_byte:
|
||||
jsr get_crunched_byte
|
||||
bcs literal_byte_gotten
|
||||
.ENDIF
|
||||
.IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE <> 0
|
||||
; -------------------------------------------------------------------
|
||||
; the static stable used for bits+offset for lengths 1, 2 and 3 (3 bytes)
|
||||
; bits 2, 4, 4 and offsets 64, 48, 32 corresponding to
|
||||
; %10010000, %11100011, %11100010
|
||||
tabl_bit:
|
||||
.BYTE $90, $e3, $e2
|
||||
.ELSE
|
||||
; -------------------------------------------------------------------
|
||||
; the static stable used for bits+offset for lengths 1 and 2 (2 bytes)
|
||||
; bits 2, 4 and offsets 48, 32 corresponding to %10001100, %11100010
|
||||
tabl_bit:
|
||||
.BYTE $8c, $e2
|
||||
.ENDIF
|
||||
|
||||
.IF ENABLE_SPLIT_ENCODING <> 0
|
||||
split_init_zp:
|
||||
mac_init_zp
|
||||
rts
|
||||
.ENDIF
|
||||
; -------------------------------------------------------------------
|
||||
; end of decruncher
|
||||
; -------------------------------------------------------------------
|
||||
|
||||
; -------------------------------------------------------------------
|
||||
; this 156 (204) byte table area may be relocated. It may also be
|
||||
; clobbered by other data between decrunches.
|
||||
; -------------------------------------------------------------------
|
||||
decrunch_table:
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE <> 0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.ENDIF
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
.byte 0,0,0,0,0,0,0,0,0,0,0,0
|
||||
; -------------------------------------------------------------------
|
||||
; end of decruncher
|
||||
; -------------------------------------------------------------------
|
||||
180
loader/src/decompress/lcdecomp.s
Executable file
180
loader/src/decompress/lcdecomp.s
Executable file
|
|
@ -0,0 +1,180 @@
|
|||
|
||||
; the following depack code is
|
||||
; written by Marek Matula (MMS/Taboo)
|
||||
; in its original form and has been
|
||||
; slightly modified
|
||||
|
||||
; compress using taboo levelcrush or
|
||||
; crush.exe by taboo,
|
||||
; don't forget to convert the
|
||||
; compressed files (not needed for mem-decompressing)
|
||||
|
||||
|
||||
; Level-crusher v1.0/v1.1 depacker
|
||||
; (c)1998 Taboo Productions!
|
||||
; All rights reserved
|
||||
|
||||
LC_SPEED = 6
|
||||
|
||||
byte = DECOMPVARS+$00
|
||||
hi = DECOMPVARS+$01
|
||||
dest = decdestlo
|
||||
desth = decdesthi
|
||||
|
||||
decompress:
|
||||
jsr getbyte
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
adc loadaddroffslo
|
||||
php
|
||||
.endif
|
||||
storedadrl: sta dest
|
||||
jsr getbyte
|
||||
.if LOADCOMPD_TO
|
||||
plp
|
||||
adc loadaddroffshi
|
||||
.endif
|
||||
storedadrh: sta desth
|
||||
|
||||
ldx #$00
|
||||
stx byte
|
||||
jp18: stx hi
|
||||
lda #$01
|
||||
asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
bcs jp2
|
||||
jp4: asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
bcs jp3
|
||||
asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
rol a
|
||||
rol hi
|
||||
bpl jp4
|
||||
jp3: tax
|
||||
beq jp5
|
||||
|
||||
; literal run
|
||||
ldy #$00
|
||||
literalrun: jsr getbyte
|
||||
sta (dest),y
|
||||
inc dest
|
||||
bne :+
|
||||
inc desth
|
||||
: dex
|
||||
bne literalrun
|
||||
jp5: cpx hi
|
||||
dec hi
|
||||
bcc literalrun
|
||||
stx hi
|
||||
|
||||
jp2: lda #$01
|
||||
asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
bcc jp9
|
||||
jp8: asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
bcs jp10
|
||||
asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
rol a
|
||||
bcc jp8
|
||||
|
||||
; decompression finished
|
||||
rts
|
||||
|
||||
jp9: inx
|
||||
jp10: adc #$01
|
||||
sta depseqle
|
||||
txa
|
||||
asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
rol a
|
||||
asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
rol a
|
||||
tay
|
||||
lda #$00
|
||||
jp12: ldx tab,y
|
||||
jp11: asl byte
|
||||
bne *+$05
|
||||
jsr getbit
|
||||
rol a
|
||||
rol hi
|
||||
dex
|
||||
bne jp11
|
||||
dey
|
||||
bmi jp14
|
||||
cpy #$03
|
||||
clc
|
||||
beq jp14
|
||||
adc #$01
|
||||
bcc jp12
|
||||
inc hi
|
||||
bcs jp12
|
||||
jp14: adc depseqle
|
||||
bcc jp15
|
||||
inc hi
|
||||
|
||||
; copy sequence
|
||||
jp15: clc
|
||||
sbc dest
|
||||
eor #$ff
|
||||
sta depseqcp+$01
|
||||
lda hi
|
||||
sbc desth
|
||||
eor #$ff
|
||||
sta depseqcp+$02
|
||||
ldy #$00
|
||||
depseqcp: lda $00,y
|
||||
sta (dest),y
|
||||
iny
|
||||
depseqle = *+$01
|
||||
cpy #$00
|
||||
bne depseqcp
|
||||
tya
|
||||
clc
|
||||
adc dest
|
||||
sta dest
|
||||
bcc jp17
|
||||
inc desth
|
||||
jp17: jmp jp18
|
||||
|
||||
getbit: pha
|
||||
jsr getbyte
|
||||
sec
|
||||
rol a
|
||||
sta byte
|
||||
pla
|
||||
jp19: rts
|
||||
|
||||
tab:
|
||||
.if LC_SPEED = 6
|
||||
.byte 4,3,3,3,4,2,2,2
|
||||
.endif
|
||||
.if LC_SPEED = 5
|
||||
.byte 4,2,3,3,4,2,2,2
|
||||
.endif
|
||||
.if LC_SPEED = 4
|
||||
.byte 4,2,2,3,4,2,2,2
|
||||
.endif
|
||||
.if LC_SPEED = 3
|
||||
.byte 4,2,2,2,4,2,2,2
|
||||
.endif
|
||||
.if LC_SPEED = 2
|
||||
.byte 3,2,2,2,3,2,2,2
|
||||
.endif
|
||||
.if LC_SPEED = 1
|
||||
.byte 3,1,2,2,3,1,2,2
|
||||
.endif
|
||||
.if LC_SPEED = 0
|
||||
.byte 2,2,1,1,2,2,1,1
|
||||
.endif
|
||||
334
loader/src/decompress/lzsa2decomp.s
Normal file
334
loader/src/decompress/lzsa2decomp.s
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
|
||||
; with slight modifications by Krill/Plush
|
||||
|
||||
.FEATURE labels_without_colons, leading_dot_in_identifiers
|
||||
|
||||
decompress = .loadcomp_entry
|
||||
decompsrc = lzsa_srcptr
|
||||
|
||||
.if MEM_DECOMP_TO_API
|
||||
; cannot copy remaining uncompressed blob of unknown size
|
||||
.error "***** MEM_DECOMP_TO_API is not supported for LZSA2. Copy compressed data to original location, then use MEM_DECOMP_API to decompress in-place. *****"
|
||||
.endif
|
||||
|
||||
BITFIRE_ZP_ADDR = DECOMPVARS - 1
|
||||
|
||||
.define asr alr
|
||||
|
||||
lzsa2_get_byte:
|
||||
lda (lzsa_srcptr),y ;Subroutine version for when
|
||||
inc <lzsa_srcptr + 0 ;inlining isn't advantageous.
|
||||
beq .lz_next_page
|
||||
rts
|
||||
.lz_next_page
|
||||
inc <lzsa_srcptr + 1 ;Inc & test for bank overflow.
|
||||
.lz_next_page_
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
GETBLOCK <lzsa_srcptr + 1
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rts
|
||||
|
||||
.loadcomp_entry
|
||||
jsr .lz_next_page_ ;shuffle in data first
|
||||
|
||||
; ldy #$00 ;Initialize source index.
|
||||
ldx #$04
|
||||
:
|
||||
jsr lzsa2_get_byte
|
||||
dex
|
||||
sta <lzsa_dstptr + 0,x
|
||||
bne :-
|
||||
|
||||
.if LOADCOMPD_TO
|
||||
ldx #2
|
||||
:
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc <lzsa_dstptr,x
|
||||
sta <lzsa_dstptr,x
|
||||
lda loadaddroffshi
|
||||
adc <lzsa_dstptr + 1,x
|
||||
sta <lzsa_dstptr + 1,x
|
||||
dex
|
||||
dex
|
||||
bpl :-
|
||||
ldx #0
|
||||
.endif
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
;
|
||||
; Copyright (C) 2019 Emmanuel Marty
|
||||
;
|
||||
; 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.
|
||||
;
|
||||
; Original software by Emmanuel Marty, altered by Tobias Bindhammer
|
||||
; to adopt it to bitfire, includes optimization in size and speed and
|
||||
; changes to the encoded format
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
lzsa_cmdbuf = BITFIRE_ZP_ADDR + 1 ;1 byte.
|
||||
lzsa_nibflg = BITFIRE_ZP_ADDR + 2 ;1 byte.
|
||||
lzsa_nibble = BITFIRE_ZP_ADDR + 3 ;1 byte.
|
||||
lzsa_offset = BITFIRE_ZP_ADDR + 4 ;1 word.
|
||||
lzsa_winptr = BITFIRE_ZP_ADDR + 6 ;1 word.
|
||||
lzsa_srcptr = BITFIRE_ZP_ADDR + 8 ;1 word.
|
||||
lzsa_dstptr = BITFIRE_ZP_ADDR + 10 ;1 word.
|
||||
lzsa_endptr = BITFIRE_ZP_ADDR + 12 ;1 word.
|
||||
lzsa_length = lzsa_winptr + 0
|
||||
lzsa_tmp = lzsa_winptr + 1
|
||||
|
||||
;command byte:
|
||||
;765 432 10
|
||||
;ttt mmm ll
|
||||
;this saves an lsr in .asm - with xyzllmmm we would need 3 lsr, now we need two lsr
|
||||
|
||||
;ll literals length
|
||||
;mmm match length
|
||||
|
||||
.depacker_start
|
||||
;XXX TODO can be saved when used with filename? or if it exits cleared
|
||||
lzsa2_depack
|
||||
sty <lzsa_nibflg ;Initialize nibble buffer.
|
||||
|
||||
;
|
||||
;Copy bytes from compressed source data.
|
||||
;
|
||||
;Hi-byte of length or offset.
|
||||
.cp_length
|
||||
jsr lzsa2_get_byte
|
||||
sta <lzsa_cmdbuf ;Preserve this for later.
|
||||
|
||||
and #$03 ;Extract literal length.
|
||||
beq .lz_offset ;size = 0 -> no literal, continue with match
|
||||
|
||||
cmp #$03 ;Extended length?
|
||||
bne .got_cp_len ;1..2
|
||||
jsr .get_length ;x is set by .get_length
|
||||
beq .put_cp_len
|
||||
.got_cp_len
|
||||
inx ;Increment # of pages to copy.
|
||||
.put_cp_len
|
||||
stx <lzsa_length
|
||||
tax ;low byte
|
||||
.cp_page
|
||||
;.lz_ptr1
|
||||
; lda $face,x
|
||||
; sta (dst),y
|
||||
; inx
|
||||
; bne +
|
||||
; jsr .lz_next_page
|
||||
;+
|
||||
; iny
|
||||
; cpy #$00
|
||||
; bne .cp_page
|
||||
; tya
|
||||
; clc
|
||||
; adc <lzsa_dstptr + 0
|
||||
; sta <lzsa_dstptr + 0
|
||||
; bcc +
|
||||
; inc <özsa_dstptr + 1
|
||||
;+
|
||||
; dec <lzsa_length
|
||||
; bne .cp_page
|
||||
|
||||
lda (lzsa_srcptr),y
|
||||
;saves another 6 bytes if used here, then single point of change
|
||||
;jsr lzsa2_get_byte
|
||||
sta (lzsa_dstptr),y
|
||||
|
||||
inc <lzsa_srcptr + 0
|
||||
bne .skip1
|
||||
jsr .lz_next_page
|
||||
.skip1
|
||||
inc <lzsa_dstptr + 0
|
||||
bne .skip2
|
||||
inc <lzsa_dstptr + 1
|
||||
.skip2
|
||||
dex
|
||||
bne .cp_page
|
||||
dec <lzsa_length ;Any full pages left to copy?
|
||||
bne .cp_page
|
||||
|
||||
;ttt token for match offset len
|
||||
;codepath 1
|
||||
;0m0 5-bit offset - m goes into first bit of offset + one nibble is read ;11111111 111mnnnn
|
||||
;0m1 13-bit offset - m goes into first bit of offset + one nibble and on byte is read ;111mnnnn bbbbbbbb
|
||||
|
||||
;codepath 2
|
||||
;10m 9-bit offset - m goes into first bit of offset + one byte is read ;1111111m bbbbbbbb
|
||||
;110 16-bit offset - two bytes are read ;bbbbbbbb bbbbbbbb
|
||||
;111 repeat offset
|
||||
|
||||
;fetch a nibble
|
||||
;13,9,16 -> fetch a lowbyte
|
||||
;9 bit fetch a bit
|
||||
;16 -> fetch a highbyte
|
||||
;rep, skip all
|
||||
|
||||
.lz_offset
|
||||
lda <lzsa_cmdbuf
|
||||
asl
|
||||
bcc .get_5_13_bits ;prefer path with 3 options over path with 2 options
|
||||
.get_9_16_rep
|
||||
asl
|
||||
bcc .get_9_bits
|
||||
.get_16_rep
|
||||
bmi .lz_length ;Repeat previous offset.
|
||||
.get_16_bits
|
||||
jsr lzsa2_get_byte ;Get hi-byte of offset.
|
||||
bne .get_low8
|
||||
.get_9_bits
|
||||
asl
|
||||
lda #$ff ;-> $ff/$fe
|
||||
rol
|
||||
bne .get_low8 ;BRA
|
||||
.get_5_13_bits
|
||||
sta <lzsa_tmp
|
||||
jsr lzsa2_get_nibble
|
||||
asl <lzsa_tmp ;shift in bit 5/13
|
||||
rol
|
||||
asl <lzsa_tmp ;shift in token bit to decide 5/13
|
||||
dex ;x = $ff
|
||||
bcc .get_low0 ;all done for 5-bit offset
|
||||
sbc #2 ;Subtract 512 because 13-bit - this extends the range for 13 bits offsets, as 0..511 is covered by 9 bit matches
|
||||
;offset starts at $FE00.
|
||||
.get_low8
|
||||
tax
|
||||
jsr lzsa2_get_byte
|
||||
.get_low0
|
||||
sta <lzsa_offset + 0
|
||||
stx <lzsa_offset + 1 ;Save new offset.
|
||||
|
||||
;
|
||||
;Copy bytes from decompressed window.
|
||||
;
|
||||
;N.B. X=0 is expected and guaranteed when we get here.
|
||||
;
|
||||
|
||||
.lz_length
|
||||
ldx #$00 ;Hi-byte of length.
|
||||
lda <lzsa_cmdbuf
|
||||
lsr
|
||||
asr #$0e ;extract match len and clear C
|
||||
adc #$02 ;correct length
|
||||
cmp #$09 ;Extended length?
|
||||
bne .got_lz_len ;a = 2 .. 8, C = 0
|
||||
jsr .get_length ;x is set by .get_length, y is still 0
|
||||
clc
|
||||
beq .calc_lz_addr ;only need to check for zero here
|
||||
.got_lz_len ;C = 0
|
||||
eor #$ff ;Negate the lo-byte of length
|
||||
tay
|
||||
iny
|
||||
eor #$ff ;restore A, a bit ugly
|
||||
inx ;Increment # of pages to copy.
|
||||
;clc ;Calc destination for partial page
|
||||
adc <lzsa_dstptr + 0
|
||||
sta <lzsa_dstptr + 0
|
||||
bcs .calc_lz_addr_
|
||||
dec <lzsa_dstptr + 1
|
||||
.calc_lz_addr
|
||||
lda <lzsa_dstptr + 0 ;N.B. Offset is negative!
|
||||
.calc_lz_addr_
|
||||
clc ;Calc address of match.
|
||||
adc <lzsa_offset + 0
|
||||
sta <lzsa_winptr + 0
|
||||
lda <lzsa_dstptr + 1
|
||||
adc <lzsa_offset + 1
|
||||
sta <lzsa_winptr + 1
|
||||
.lz_page
|
||||
lda (lzsa_winptr),y
|
||||
sta (lzsa_dstptr),y
|
||||
iny
|
||||
bne .lz_page
|
||||
inc <lzsa_winptr + 1
|
||||
inc <lzsa_dstptr + 1
|
||||
dex ;Any full pages left to copy?
|
||||
bne .lz_page
|
||||
|
||||
lda <lzsa_srcptr + 0
|
||||
eor <lzsa_endptr + 0
|
||||
bne .lz_poll
|
||||
eor <lzsa_srcptr + 1
|
||||
eor <lzsa_endptr + 1
|
||||
beq .finished2
|
||||
.lz_skip_end
|
||||
jmp .cp_length ;Loop around to the beginning.
|
||||
|
||||
.lz_poll
|
||||
POLLBLOCK
|
||||
; ldy #0
|
||||
ldx #$00 ;clear x afterwards, yet a bit annoying, y stays 0
|
||||
beq .lz_skip_end
|
||||
|
||||
.get_length
|
||||
;entered with x = 0
|
||||
adc #$0e ;C = 1 -> adc #$0f
|
||||
sta <lzsa_tmp
|
||||
jsr lzsa2_get_nibble
|
||||
adc #$00 ;C = 1
|
||||
beq .byte_length ;Extended length?
|
||||
adc <lzsa_tmp ;C = 0 from addition above -> $10 + lzsa_tmp
|
||||
.got_length ;Z-flag is set
|
||||
rts ;lengths.
|
||||
|
||||
.byte_length
|
||||
jsr lzsa2_get_byte ;So rare, this can be slow!
|
||||
clc ;adc #$0f + 0
|
||||
adc <lzsa_tmp
|
||||
bcc .got_length
|
||||
beq .finished
|
||||
.word_length
|
||||
;this is fetched big-endian, to avoid pha/pla, saves code
|
||||
jsr lzsa2_get_byte ;So rare, this can be slow!
|
||||
tax
|
||||
jsr lzsa2_get_byte ;So rare, this can be slow!
|
||||
and #$ff ;restore z-flag
|
||||
rts
|
||||
.finished
|
||||
pla ;Decompression completed, pop
|
||||
pla ;return address.
|
||||
.finished2
|
||||
rts
|
||||
|
||||
;
|
||||
;Get a nibble value from compressed data in A.
|
||||
;
|
||||
|
||||
;XXX TODO pack nibbles in another way? -> 10101010 -> first nibble = and #$55, second nibble = asr #$aa?
|
||||
lzsa2_get_nibble
|
||||
lsr <lzsa_nibflg ;Is there a nibble waiting?
|
||||
lda <lzsa_nibble ;Extract the lo-nibble.
|
||||
bcs .got_nibble
|
||||
|
||||
inc <lzsa_nibflg ;Reset the flag.
|
||||
|
||||
jsr lzsa2_get_byte
|
||||
|
||||
sta <lzsa_nibble ;Preserve for next time.
|
||||
lsr ;Extract the hi-nibble.
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sec
|
||||
.got_nibble
|
||||
ora #$f0
|
||||
rts
|
||||
344
loader/src/decompress/ncdecomp.s
Executable file
344
loader/src/decompress/ncdecomp.s
Executable file
|
|
@ -0,0 +1,344 @@
|
|||
;
|
||||
; NuCrunch 1.0
|
||||
; Christopher Jam
|
||||
; May 2018
|
||||
; with slight modifications by Krill
|
||||
;
|
||||
|
||||
decompress = decrunch
|
||||
decompsrc = read+1
|
||||
|
||||
NC_BLOCK_INTERFACE = 1
|
||||
|
||||
.macro getByte1
|
||||
jsr get_byte
|
||||
.endmacro
|
||||
|
||||
.macro getBit1
|
||||
.local nomore
|
||||
asl zbs1
|
||||
bne nomore
|
||||
getByte1
|
||||
sec
|
||||
rol
|
||||
sta zbs1
|
||||
nomore:
|
||||
.endmacro
|
||||
|
||||
; get head of a pair of bits from the bitpair stream
|
||||
; (must getBit2t precisely once before invoking again)
|
||||
|
||||
.macro getBit2h
|
||||
.local nomore
|
||||
asl zbs2
|
||||
bne nomore
|
||||
getByte1
|
||||
sec
|
||||
rol
|
||||
sta zbs2
|
||||
nomore:
|
||||
.endmacro
|
||||
|
||||
.if NC_BLOCK_INTERFACE
|
||||
; same, but preserving A
|
||||
.macro getBit2hpa
|
||||
.local nomore
|
||||
asl zbs2
|
||||
bne nomore
|
||||
pha
|
||||
getByte1
|
||||
sec
|
||||
rol
|
||||
sta zbs2
|
||||
pla
|
||||
nomore:
|
||||
.endmacro
|
||||
.else
|
||||
; same, but preserving A/ trashing X.
|
||||
.macro getBit2hpa
|
||||
.local nomore
|
||||
asl zbs2
|
||||
bne nomore
|
||||
tax
|
||||
getByte1
|
||||
sec
|
||||
rol
|
||||
sta zbs2
|
||||
txa
|
||||
nomore:
|
||||
.endmacro
|
||||
.endif
|
||||
|
||||
; get tail of a pair of bits from the bitpair stream
|
||||
.macro getBit2t
|
||||
asl zbs2
|
||||
.endmacro
|
||||
|
||||
; get head of a quad of bits from the quad stream
|
||||
; (must getBit4t precisely three times before invoking again)
|
||||
|
||||
.macro getBit4h
|
||||
.local nomore
|
||||
asl zbs4
|
||||
bne nomore
|
||||
getByte1
|
||||
sec
|
||||
rol
|
||||
sta zbs4
|
||||
nomore:
|
||||
.endmacro
|
||||
|
||||
|
||||
; get tail of a quad of bits from the quad stream
|
||||
.macro getBit4t
|
||||
asl zbs4
|
||||
.endmacro
|
||||
|
||||
; note, trashes X. Also, carry is clear when done
|
||||
.macro getExpGoulombTail
|
||||
.local ndone
|
||||
ndone:
|
||||
getBit2hpa
|
||||
rol
|
||||
getBit2t
|
||||
bcs ndone
|
||||
.endmacro
|
||||
|
||||
.macro getExpGoulombTail_odd_aligned
|
||||
.local ndone
|
||||
ndone:
|
||||
getBit2t
|
||||
rol
|
||||
getBit2hpa
|
||||
bcs ndone
|
||||
.endmacro
|
||||
|
||||
.ifdef NUCRUNCH_ALIGN_FOR_SPEED
|
||||
.byte <-$64-*,0 ; place decode_copy on a page boundary
|
||||
.endif
|
||||
|
||||
decrunch_zpa=DECOMPVARS ;5 bytes required
|
||||
zbs1 = decrunch_zpa+$00 ; 1 byte
|
||||
zbs2 = decrunch_zpa+$01 ; 1 byte
|
||||
zbs4 = decrunch_zpa+$02 ; 1 byte
|
||||
zpc = decrunch_zpa+$03 ; 2 bytes
|
||||
zpd = decdestlo
|
||||
|
||||
offsetm1 = zpc ; these are aliased, as never need both
|
||||
|
||||
|
||||
decrunch:
|
||||
; ldy #0
|
||||
sty zbs1
|
||||
sty zbs2
|
||||
sty zbs4
|
||||
|
||||
|
||||
decrunch_next_group:
|
||||
.if NC_BLOCK_INTERFACE
|
||||
jsr read_init
|
||||
lda loadaddrhi
|
||||
sta literal_read+2
|
||||
ldx loadaddrlo
|
||||
.endif
|
||||
next_segment:
|
||||
jsr get_byte
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
adc loadaddroffslo
|
||||
php
|
||||
.endif
|
||||
storedadrl:
|
||||
sta zpd+0
|
||||
jsr get_byte
|
||||
.if LOADCOMPD_TO
|
||||
plp
|
||||
adc loadaddroffshi
|
||||
.endif
|
||||
storedadrh:
|
||||
sta zpd+1
|
||||
|
||||
decode_literal:
|
||||
|
||||
; get count [ExpGoulomb0+1] in x
|
||||
.if NC_BLOCK_INTERFACE
|
||||
getBit1
|
||||
lda#1
|
||||
bcc ret1
|
||||
getExpGoulombTail
|
||||
ret1:
|
||||
sta literal_len + 1
|
||||
.else
|
||||
ldx#1
|
||||
getBit1
|
||||
bcc ret1
|
||||
lda#1
|
||||
getExpGoulombTail
|
||||
tax
|
||||
ret1:
|
||||
.endif
|
||||
|
||||
literal_loop:
|
||||
.if NC_BLOCK_INTERFACE
|
||||
literal_read:
|
||||
lda $ff00,x
|
||||
inx
|
||||
bne *+5
|
||||
jsr read_inc
|
||||
.else
|
||||
decompgetbyte:
|
||||
jsr getcmem
|
||||
.endif
|
||||
sta (zpd),y
|
||||
iny
|
||||
.if NC_BLOCK_INTERFACE
|
||||
literal_len:
|
||||
cpy #0
|
||||
.else
|
||||
dex
|
||||
.endif
|
||||
bne literal_loop
|
||||
|
||||
clc
|
||||
tya
|
||||
adc zpd
|
||||
sta zpd
|
||||
bcc *+4
|
||||
inc zpd+1
|
||||
|
||||
ldy#0
|
||||
; literal is always followed by copy
|
||||
|
||||
decode_copy:
|
||||
getBit2h
|
||||
bcc short_offset
|
||||
lda#1
|
||||
getExpGoulombTail_odd_aligned
|
||||
adc#255
|
||||
sta offsetm1+1
|
||||
getByte1
|
||||
sta offsetm1
|
||||
jmp got_high
|
||||
|
||||
short_offset:
|
||||
lda#0
|
||||
sta offsetm1+1
|
||||
|
||||
;ExpGoulomb k=3
|
||||
getBit4h
|
||||
lda#1
|
||||
bcc no_tail
|
||||
getExpGoulombTail_odd_aligned
|
||||
no_tail:
|
||||
adc#255
|
||||
|
||||
getBit4t
|
||||
rol
|
||||
getBit4t
|
||||
rol
|
||||
getBit4t
|
||||
rol
|
||||
sta offsetm1
|
||||
got_high:
|
||||
|
||||
.if NC_BLOCK_INTERFACE
|
||||
lda#1
|
||||
getBit2t
|
||||
bcc length_two
|
||||
getExpGoulombTail
|
||||
cmp#255
|
||||
beq end_of_segment ; copy length of 256 marks end of segment
|
||||
length_two:
|
||||
sta copy_len+1
|
||||
.else
|
||||
ldx#1
|
||||
getBit2t
|
||||
bcc length_two
|
||||
lda#1
|
||||
getExpGoulombTail
|
||||
tax
|
||||
cpx#255
|
||||
beq end_of_segment ; copy length of 256 marks end of segment
|
||||
length_two:
|
||||
.endif
|
||||
|
||||
; note carry is clear at this point; good as we want to subtract (offsetm1+1)
|
||||
lda zpd
|
||||
sbc offsetm1
|
||||
sta zpc
|
||||
|
||||
lda zpd+1
|
||||
sbc offsetm1+1
|
||||
sta zpc+1
|
||||
|
||||
lda (zpc),y
|
||||
sta (zpd),y
|
||||
copy_loop:
|
||||
iny
|
||||
lda (zpc),y
|
||||
sta (zpd),y
|
||||
.if NC_BLOCK_INTERFACE
|
||||
copy_len:
|
||||
cpy #0
|
||||
.else
|
||||
dex
|
||||
.endif
|
||||
bne copy_loop
|
||||
tya
|
||||
|
||||
; carry will be set from SBC above
|
||||
adc zpd
|
||||
sta zpd
|
||||
bcc *+4
|
||||
inc zpd+1
|
||||
|
||||
.if NC_BLOCK_INTERFACE
|
||||
POLLBLOCK
|
||||
.endif
|
||||
|
||||
ldy#0
|
||||
getBit1
|
||||
bcs jmp_decode_copy
|
||||
jmp decode_literal
|
||||
jmp_decode_copy:
|
||||
jmp decode_copy
|
||||
|
||||
get_byte:
|
||||
.if NC_BLOCK_INTERFACE
|
||||
read:
|
||||
lda $ff00,x
|
||||
inx
|
||||
beq read_inc
|
||||
rts
|
||||
read_inc:
|
||||
inc literal_read+2
|
||||
inc read+2
|
||||
read_init:
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
GETBLOCK read+2
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
ldx#0
|
||||
end_of_segment:
|
||||
rts
|
||||
|
||||
.else
|
||||
decompgetbyte1:
|
||||
jmp getcmem
|
||||
.endif
|
||||
.if NC_BLOCK_INTERFACE
|
||||
.else
|
||||
end_of_file:
|
||||
rts
|
||||
end_of_segment:
|
||||
lda offsetm1
|
||||
cmp#0
|
||||
beq end_of_file
|
||||
jmp next_segment
|
||||
.endif
|
||||
|
||||
decrunch_end:
|
||||
|
||||
261
loader/src/decompress/pudecomp.s
Executable file
261
loader/src/decompress/pudecomp.s
Executable file
|
|
@ -0,0 +1,261 @@
|
|||
|
||||
; The following depack code is
|
||||
; written by Pasi Ojala (Albert/PU239)
|
||||
; in its original form and has been
|
||||
; slightly modified.
|
||||
|
||||
; The original routine was located at
|
||||
; http://www.cs.tut.fi/~albert/Dev/pucrunch/sa_uncrunch.asm
|
||||
; at the time of writing.
|
||||
|
||||
; crunch using the -c0 switch
|
||||
|
||||
.define OLD_VERSION 0; pre 2004/3/24, this includes http://www.cs.tut.fi/~albert/Dev/pucrunch/pucrunch_x86.zip as of 2013/4/9
|
||||
|
||||
LZPOS = DECOMPVARS + $00
|
||||
bitstr = DECOMPVARS + $02
|
||||
|
||||
decompress: ldx #5
|
||||
@222: jsr getbyt ; skip 'p', 'u', endAddr HI&LO, leave starting escape in A
|
||||
dex
|
||||
bne @222
|
||||
sta esc+1 ; starting escape
|
||||
|
||||
jsr getbyt ; read startAddr
|
||||
.if MEM_DECOMP_TO_API
|
||||
ldx storedadrl
|
||||
cpx #OPC_LDA_ZP
|
||||
bne :+
|
||||
storedadrl: lda decdestlo
|
||||
:
|
||||
.endif
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
adc loadaddroffslo
|
||||
php
|
||||
.endif
|
||||
sta OUTPOS
|
||||
jsr getbyt
|
||||
.if MEM_DECOMP_TO_API
|
||||
ldx storedadrh
|
||||
cpx #OPC_LDA_ZP
|
||||
bne :+
|
||||
storedadrh: lda decdesthi
|
||||
:
|
||||
.endif
|
||||
.if LOADCOMPD_TO
|
||||
plp
|
||||
adc loadaddroffshi
|
||||
.endif
|
||||
sta OUTPOS+1
|
||||
|
||||
jsr getbyt ; read # of escape bits
|
||||
sta escB0+1
|
||||
sta escB1+1
|
||||
lda #8
|
||||
sec
|
||||
sbc escB1+1
|
||||
sta noesc+1 ; 8-escBits
|
||||
|
||||
jsr getbyt
|
||||
sta mg+1 ; maxGamma + 1
|
||||
lda #9
|
||||
sec
|
||||
sbc mg+1 ; 8 - maxGamma == (8 + 1) - (maxGamma + 1)
|
||||
sta longrle+1
|
||||
jsr getbyt
|
||||
sta mg1+1 ; (1<<maxGamma)
|
||||
asl a
|
||||
clc
|
||||
sbc #0
|
||||
sta mg21+1 ; (2<<maxGamma) - 1
|
||||
jsr getbyt
|
||||
sta elzpb+1
|
||||
|
||||
jsr getbyt ; exec address
|
||||
sta lo+1 ; lo
|
||||
jsr getbyt
|
||||
sta hi+1 ; hi
|
||||
|
||||
jsr getbyt ; rleUsed
|
||||
ldx #0
|
||||
tay
|
||||
beq @1 ; Y == 0 ?
|
||||
@0: jsr getbyt
|
||||
sta table,x
|
||||
inx
|
||||
dey
|
||||
bne @0
|
||||
@1: ; setup bit store - $80 means empty
|
||||
lda #$80
|
||||
sta bitstr
|
||||
bne main
|
||||
|
||||
getbyt: jsr getnew
|
||||
lda bitstr
|
||||
ror
|
||||
rts
|
||||
|
||||
newesc: ldy esc+1 ; remember the old code (top bits for escaped byte)
|
||||
escB0: ldx #2 ; ** PARAMETER 0..8
|
||||
jsr getchkf ; get & save the new escape code
|
||||
sta esc+1
|
||||
tya ; pre-set the bits
|
||||
; Fall through and get the rest of the bits.
|
||||
noesc: ldx #6 ; ** PARAMETER 8..0
|
||||
jsr getchkf
|
||||
jsr putch ; output the escaped/normal byte
|
||||
|
||||
; Fall through and check the escape bits again
|
||||
main: ldy #0 ; Reset to a defined state
|
||||
tya ; A = 0
|
||||
escB1: ldx #2 ; ** PARAMETER 0..8
|
||||
jsr getchkf ; X = 0
|
||||
esc: cmp #0
|
||||
bne noesc
|
||||
; Fall through to packed code
|
||||
|
||||
jsr getval ; X = 0
|
||||
sta LZPOS ; xstore - save the length for a later time
|
||||
lsr ; cmp #1 ; LEN == 2 ? (A is never 0)
|
||||
bne lz77 ; LEN != 2 -> LZ77
|
||||
;tya ; A = 0
|
||||
jsr get1bit ; X = 0
|
||||
lsr ; bit -> C, A = 0
|
||||
bcc lz77_2 ; A=0 -> LZPOS+1
|
||||
;***FALL THRU***
|
||||
|
||||
; e..e01
|
||||
jsr get1bit ; X = 0
|
||||
lsr ; bit -> C, A = 0
|
||||
bcc newesc ; e..e010
|
||||
;***FALL THRU***
|
||||
|
||||
; e..e011
|
||||
srle: iny ; Y is 1 bigger than MSB loops
|
||||
jsr getval ; Y is 1, get len, X = 0
|
||||
sta LZPOS ; xstore - Save length LSB
|
||||
mg1: cmp #64 ; ** PARAMETER 63-64 -> C clear, 64-64 -> C set..
|
||||
bcc chrcode ; short RLE, get bytecode
|
||||
|
||||
longrle: ldx #2 ; ** PARAMETER 111111xxxxxx
|
||||
jsr getbits ; get 3/2/1 more bits to get a full byte, X = 0
|
||||
sta LZPOS ; xstore - Save length LSB
|
||||
|
||||
jsr getval ; length MSB, X = 0
|
||||
tay ; Y is 1 bigger than MSB loops
|
||||
|
||||
chrcode: jsr getval ; Byte Code, X = 0
|
||||
tax ; this is executed most of the time anyway
|
||||
lda table-1,x; Saves one jump if done here (loses one txa)
|
||||
|
||||
.if OLD_VERSION
|
||||
cpx #32 ; 31-32 -> C clear, 32-32 -> C set..
|
||||
.else
|
||||
cpx #16 ; 15-16 -> C clear, 16-16 -> C set..
|
||||
.endif
|
||||
bcc @1 ; 1..31, we got the right byte from the table
|
||||
|
||||
; Ranks 32..64 (11111°xxxxx), get byte..
|
||||
txa ; get back the value (5 valid bits)
|
||||
.if OLD_VERSION
|
||||
ldx #3
|
||||
.else
|
||||
ldx #4
|
||||
.endif
|
||||
jsr getbits ; get 3 more bits to get a full byte, X = 0
|
||||
|
||||
@1: ldx LZPOS ; xstore - get length LSB
|
||||
inx ; adjust for cpx#$ff;bne -> bne
|
||||
dorle: jsr putch
|
||||
dex
|
||||
bne dorle ; xstore 0..255 -> 1..256
|
||||
dey
|
||||
bne dorle ; Y was 1 bigger than wanted originally
|
||||
mainbeq: beq main ; reverse condition -> jump always
|
||||
|
||||
|
||||
lz77: jsr getval ; X = 0
|
||||
mg21: cmp #127 ; ** PARAMETER Clears carry (is maximum value)
|
||||
bne noeof
|
||||
; EOF
|
||||
eof:
|
||||
hi: ldx #0
|
||||
lo: ldy #0
|
||||
rts
|
||||
|
||||
noeof: sbc #0 ; C is clear -> subtract 1 (1..126 -> 0..125)
|
||||
elzpb: ldx #0 ; ** PARAMETER (more bits to get)
|
||||
jsr getchkf ; clears Carry, X = 0
|
||||
lz77_2: sta LZPOS+1 ; offset MSB
|
||||
jsr get8bit ; clears Carry, X = 0
|
||||
; Note: Already eored in the compressor..
|
||||
;eor #255 ; offset LSB 2's complement -1 (i.e., -X = ~X+1)
|
||||
adc OUTPOS ; -offset -1 + curpos (C is clear)
|
||||
ldx LZPOS ; xstore = LZLEN (read before it's overwritten)
|
||||
sta LZPOS
|
||||
|
||||
lda OUTPOS+1
|
||||
sbc LZPOS+1 ; takes C into account
|
||||
sta LZPOS+1 ; copy X+1 number of chars from LZPOS to OUTPOS
|
||||
;ldy #0 ; Y was 0 originally, we don't change it
|
||||
|
||||
inx ; adjust for cpx#$ff;bne -> bne
|
||||
lzloop: lda (LZPOS),y; using abs,y is 3 bytes longer, only 1 cycle/byte faster
|
||||
jsr putch ; Note: must be copied forwards!
|
||||
iny ; Y does not wrap because X=0..255 and Y initially 0
|
||||
dex
|
||||
bne lzloop ; X loops, (256,1..255)
|
||||
beq mainbeq ; jump through another beq (-1 byte, +3 cycles)
|
||||
|
||||
|
||||
getnew: pha ; 1 Byte/3 cycles
|
||||
jsr getbyte
|
||||
sec
|
||||
rol ; Shift out the next bit and
|
||||
; shift in C=1 (last bit marker)
|
||||
sta bitstr ; bitstr initial value = $80 == empty
|
||||
pla ; 1 Byte/4 cycles
|
||||
rts
|
||||
; 25+12 = 37
|
||||
|
||||
; getval : Gets a 'static huffman coded' value
|
||||
; ** Scratches X, returns the value in A **
|
||||
getval: inx ; X <- 1
|
||||
txa ; set the top bit (value is 1..255)
|
||||
gv0: asl bitstr
|
||||
bne @1
|
||||
jsr getnew
|
||||
@1: bcc getchk ; got 0-bit
|
||||
inx
|
||||
mg: cpx #7 ; ** PARAMETER unary code maximum length + 1
|
||||
bne gv0
|
||||
beq getchk ; inverse condition -> jump always
|
||||
; getval: 18 bytes
|
||||
; 15 + 17*n + 6+15*n+12 + 36*n/8 = 33 + 32*n + 36*n/8 cycles
|
||||
|
||||
; getbits: Gets X bits from the stream
|
||||
; ** Scratches X, returns the value in A **
|
||||
get8bit: ldx #7
|
||||
get1bit: inx ;2
|
||||
getbits: asl bitstr
|
||||
bne @1
|
||||
jsr getnew
|
||||
@1: rol ;2
|
||||
getchk: dex ;2 more bits to get ?
|
||||
getchkf: bne getbits ;2/3
|
||||
clc ;2 return carry cleared
|
||||
rts ;6+6
|
||||
|
||||
OUTPOS = *+$01
|
||||
putch: sta $aaaa ; ** parameter
|
||||
inc OUTPOS ; ZP
|
||||
bne @0
|
||||
inc OUTPOS+1 ; ZP
|
||||
@0: rts
|
||||
|
||||
.if OLD_VERSION
|
||||
table: .res 31,0
|
||||
.else
|
||||
table: .res 15,0
|
||||
.endif
|
||||
491
loader/src/decompress/subsizerdecomp.s
Executable file
491
loader/src/decompress/subsizerdecomp.s
Executable file
|
|
@ -0,0 +1,491 @@
|
|||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
;* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
;* Slightly modified by Gunnar Ruthenberg <krill@plush.de>
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* subsizer 0.6 decruncher - stand alone version
|
||||
;*
|
||||
;* usage:
|
||||
;* You need to provide a function to get a byte from the input
|
||||
;* stream. (must preserve X,Y and C)
|
||||
;*
|
||||
;******
|
||||
|
||||
decompress = decrunch
|
||||
|
||||
.FEATURE leading_dot_in_identifiers
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* Configuration options
|
||||
;*
|
||||
;******
|
||||
FORWARD_DECRUNCHING = 1
|
||||
HAVE_LONG_PARTS = 1
|
||||
|
||||
|
||||
.if HAVE_LONG_PARTS
|
||||
PART_MASK = %00001111
|
||||
N_PARTS = 16
|
||||
.else
|
||||
PART_MASK = %00000111
|
||||
N_PARTS = 8
|
||||
.endif
|
||||
|
||||
|
||||
len_zp = DECOMPVARS
|
||||
copy_zp = DECOMPVARS + 1
|
||||
hibits_zp = DECOMPVARS + 3
|
||||
buf_zp = DECOMPVARS + 4
|
||||
.if MEM_DECOMP_TO_API
|
||||
dest_zp = decdestlo
|
||||
.else
|
||||
dest_zp = DECOMPVARS + 5
|
||||
.endif
|
||||
endm_zp = DECOMPVARS + 7
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME fast macros
|
||||
;*
|
||||
;******
|
||||
|
||||
;******
|
||||
;* get bit macro
|
||||
.macro get_bit
|
||||
.local .gb_skp1
|
||||
asl buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
.gb_skp1:
|
||||
.endmacro
|
||||
|
||||
|
||||
;******
|
||||
;* get bits max8 macro
|
||||
.macro get_bits_max8
|
||||
.local .gb_lp1
|
||||
.local .gb_skp1
|
||||
.gb_lp1:
|
||||
asl buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
pha
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
pla
|
||||
.gb_skp1:
|
||||
rol
|
||||
dey
|
||||
bne .gb_lp1
|
||||
.endmacro
|
||||
|
||||
|
||||
;******
|
||||
;* get bits max8 masked macro
|
||||
.macro get_bits_max8_masked
|
||||
.local .gb_lp1
|
||||
.local .gb_skp1
|
||||
.gb_lp1:
|
||||
asl buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
tay
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
tya
|
||||
.gb_skp1:
|
||||
rol
|
||||
bcs .gb_lp1
|
||||
.endmacro
|
||||
|
||||
|
||||
;******
|
||||
;* get bits max16 macro
|
||||
.macro get_bits_max16
|
||||
.local .gb_lp1
|
||||
.local .gb_skp1
|
||||
.gb_lp1:
|
||||
asl buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
pha
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
pla
|
||||
.gb_skp1:
|
||||
rol
|
||||
rol hibits_zp
|
||||
dey
|
||||
bne .gb_lp1 ; C=0 for all Y!=0
|
||||
.endmacro
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME decrunch
|
||||
;*
|
||||
;******
|
||||
decrunch:
|
||||
.if MEM_DECOMP_TO_API
|
||||
; Get endm_zp, dest_zp, and buf_zp
|
||||
dc_lp00:
|
||||
jsr dc_get_byte
|
||||
sta endm_zp
|
||||
jsr dc_get_byte
|
||||
storedadrh:
|
||||
sta dest_zp+1
|
||||
jsr dc_get_byte
|
||||
storedadrl:
|
||||
sta dest_zp+0
|
||||
jsr dc_get_byte
|
||||
sta buf_zp
|
||||
ldx #0
|
||||
.else
|
||||
ldx #4
|
||||
dc_lp00:
|
||||
jsr dc_get_byte
|
||||
sta buf_zp-1,x
|
||||
dex
|
||||
bne dc_lp00
|
||||
.endif
|
||||
; X = 0
|
||||
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc dest_zp+0
|
||||
sta dest_zp+0
|
||||
lda loadaddroffshi
|
||||
adc dest_zp+1
|
||||
sta dest_zp+1
|
||||
.endif
|
||||
|
||||
; ldx #0
|
||||
dc_lp01:
|
||||
|
||||
;******
|
||||
;* get 4 bits
|
||||
lda #%11100000
|
||||
dcg_lp1:
|
||||
asl buf_zp
|
||||
bne dcg_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
tay
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
tya
|
||||
dcg_skp1:
|
||||
rol
|
||||
bcs dcg_lp1
|
||||
; Acc = 4 bits.
|
||||
|
||||
sta bits,x
|
||||
|
||||
txa
|
||||
and #PART_MASK
|
||||
tay
|
||||
beq dc_skp01
|
||||
|
||||
lda #0
|
||||
sta hibits_zp
|
||||
ldy bits-1,x
|
||||
sec
|
||||
dc_lp02:
|
||||
rol
|
||||
rol hibits_zp
|
||||
dey
|
||||
bpl dc_lp02
|
||||
; C = 0
|
||||
; clc
|
||||
adc base_l-1,x
|
||||
tay
|
||||
lda hibits_zp
|
||||
adc base_h-1,x
|
||||
|
||||
dc_skp01:
|
||||
sta base_h,x
|
||||
tya
|
||||
sta base_l,x
|
||||
inx
|
||||
cpx #N_PARTS*4+4
|
||||
bne dc_lp01
|
||||
|
||||
; perform decrunch
|
||||
|
||||
ldy #0
|
||||
; fall through
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME decruncher
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* decruncher
|
||||
;*
|
||||
;******
|
||||
decrunch_entry:
|
||||
|
||||
;******
|
||||
;* single literal byte
|
||||
;*
|
||||
dc_literal:
|
||||
.if FORWARD_DECRUNCHING
|
||||
jsr dc_get_byte
|
||||
; ldy #0
|
||||
sta (dest_zp),y
|
||||
inc dest_zp
|
||||
bne dc_skp5
|
||||
inc dest_zp+1
|
||||
dc_skp5:
|
||||
dc_common:
|
||||
.else
|
||||
lda dest_zp
|
||||
bne dc_skp5
|
||||
dec dest_zp+1
|
||||
dc_skp5:
|
||||
dec dest_zp
|
||||
jsr dc_get_byte
|
||||
; ldy #0
|
||||
dc_common:
|
||||
sta (dest_zp),y
|
||||
.endif
|
||||
; fall through
|
||||
|
||||
decrunch_main:
|
||||
|
||||
;------
|
||||
; perform actual decrunch
|
||||
dc_lp1:
|
||||
get_bit
|
||||
bcs dc_literal
|
||||
|
||||
; get length as bits/base.
|
||||
ldx #$80-N_PARTS
|
||||
dc_lp2:
|
||||
inx
|
||||
bmi dc_skp0
|
||||
get_bit
|
||||
bcc dc_lp2
|
||||
clc
|
||||
dc_skp0:
|
||||
; C = 0, Y = 0
|
||||
; lda #0
|
||||
tya
|
||||
ldy bits_len-$80+N_PARTS-1,x
|
||||
beq dcb1_skp2
|
||||
get_bits_max8
|
||||
dcb1_skp2:
|
||||
; C = 0
|
||||
adc base_len-$80+N_PARTS-1,x
|
||||
sta len_zp
|
||||
; C = 0
|
||||
|
||||
|
||||
.if FORWARD_DECRUNCHING
|
||||
tax
|
||||
.else
|
||||
;******
|
||||
;* IN: len = $01..$100 (Acc = $00..$ff)
|
||||
;* OUT: dest_zp = dest_zp - len, X = len-1
|
||||
;*
|
||||
tax
|
||||
; clc
|
||||
eor #$ff
|
||||
adc dest_zp
|
||||
sta dest_zp
|
||||
bcs dc_skp22
|
||||
dec dest_zp+1
|
||||
dc_skp22:
|
||||
.endif
|
||||
|
||||
; check end marker here to avoid thrashing carry earlier
|
||||
cpx endm_zp
|
||||
beq done
|
||||
|
||||
;******
|
||||
;* Get selector bits depending on length.
|
||||
;*
|
||||
;* IN: len = $01..$100 (X = $00..$ff)
|
||||
;* OUT:
|
||||
;*
|
||||
cpx #4
|
||||
bcc dc_skp2
|
||||
ldx #3
|
||||
dc_skp2:
|
||||
|
||||
; get offset as bits/base.
|
||||
lda tabb,x
|
||||
get_bits_max8_masked
|
||||
tax
|
||||
; C = 0
|
||||
|
||||
lda #0
|
||||
sta hibits_zp
|
||||
ldy bits_offs,x
|
||||
beq dcb3_skp2
|
||||
get_bits_max16
|
||||
dcb3_skp2:
|
||||
; C = 0, Acc/hibits_zp + base_offs,x = offset - 1
|
||||
|
||||
.if FORWARD_DECRUNCHING
|
||||
adc base_offs_l,x
|
||||
bcc dcb3_skp3
|
||||
inc hibits_zp
|
||||
clc
|
||||
dcb3_skp3:
|
||||
eor #$ff
|
||||
adc dest_zp
|
||||
sta copy_zp
|
||||
lda dest_zp+1
|
||||
sbc hibits_zp
|
||||
sbc base_offs_h,x
|
||||
sta copy_zp+1
|
||||
.else
|
||||
; perform: copy_zp = Acc/hibits_zp + base_offs,x + 1 + dest_zp
|
||||
; result: copy_zp = dest_zp + offset
|
||||
adc base_offs_l,x
|
||||
bcc dcb3_skp3
|
||||
inc hibits_zp
|
||||
dcb3_skp3:
|
||||
sec
|
||||
adc dest_zp
|
||||
sta copy_zp
|
||||
lda hibits_zp
|
||||
adc base_offs_h,x
|
||||
; C = 0
|
||||
adc dest_zp+1
|
||||
sta copy_zp+1
|
||||
.endif
|
||||
|
||||
.if FORWARD_DECRUNCHING
|
||||
copy:
|
||||
.if 1
|
||||
; this is shorter
|
||||
ldx len_zp
|
||||
inx
|
||||
ldy #$ff
|
||||
dc_lp4:
|
||||
iny
|
||||
lda (copy_zp),y
|
||||
sta (dest_zp),y
|
||||
dex
|
||||
bne dc_lp4
|
||||
.else
|
||||
; and this might be faster on average, as there are many 1-byte sequences
|
||||
ldy len_zp
|
||||
beq dc_skp4
|
||||
ldx len_zp
|
||||
ldy #$00
|
||||
dc_lp4:
|
||||
lda (copy_zp),y
|
||||
sta (dest_zp),y
|
||||
iny
|
||||
dex
|
||||
bne dc_lp4
|
||||
dc_skp4:
|
||||
lda (copy_zp),y
|
||||
sta (dest_zp),y
|
||||
.endif
|
||||
; C = 1
|
||||
tya
|
||||
adc dest_zp
|
||||
sta dest_zp
|
||||
bcc dc_skp22
|
||||
inc dest_zp+1
|
||||
dc_skp22:
|
||||
ldy #$00
|
||||
.else
|
||||
;******
|
||||
;* Reverse fast copy
|
||||
;*
|
||||
;* IN: len = $01..$100 (len_zp = $00..$ff), C = 0
|
||||
;*
|
||||
copy:
|
||||
ldy len_zp
|
||||
beq dc_skp4
|
||||
dc_lp4:
|
||||
lda (copy_zp),y
|
||||
sta (dest_zp),y
|
||||
dey
|
||||
bne dc_lp4
|
||||
dc_skp4:
|
||||
lda (copy_zp),y
|
||||
; sta (dest_zp),y
|
||||
.endif
|
||||
|
||||
jmp dc_common
|
||||
; bcc dc_common ; always taken
|
||||
|
||||
;******
|
||||
;* exit out
|
||||
done:
|
||||
rts
|
||||
|
||||
.if HAVE_LONG_PARTS
|
||||
tabb:
|
||||
.byte %10000000 | (48 >> 2) ; 2 bits
|
||||
.byte %11100000 | (0 >> 4) ; 4 bits
|
||||
.byte %11100000 | (16 >> 4) ; 4 bits
|
||||
.byte %11100000 | (32 >> 4) ; 4 bits
|
||||
.else
|
||||
tabb:
|
||||
.byte %10000000 | (24 >> 2) ; 2 bits
|
||||
.byte %11000000 | (0 >> 3) ; 3 bits
|
||||
.byte %11000000 | (8 >> 3) ; 3 bits
|
||||
.byte %11000000 | (16 >> 3) ; 3 bits
|
||||
.endif
|
||||
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME dc_get_byte
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Get byte from the packed stream.
|
||||
;*
|
||||
;******
|
||||
dc_get_byte = getbyte
|
||||
|
||||
end_decruncher:
|
||||
|
||||
begin_tables:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME base_l, base_h, bits
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Data for bits/base decoding.
|
||||
;*
|
||||
;******
|
||||
base_l:
|
||||
base_len:
|
||||
.res N_PARTS,0
|
||||
base_offs_l:
|
||||
.res N_PARTS*3+4,0
|
||||
base_h = * - N_PARTS
|
||||
; .res N_PARTS,0
|
||||
base_offs_h:
|
||||
.res N_PARTS*3+4,0
|
||||
|
||||
bits:
|
||||
bits_len:
|
||||
.res N_PARTS,0
|
||||
bits_offs:
|
||||
.res N_PARTS*3+4,0
|
||||
|
||||
end_tables:
|
||||
|
||||
; eof
|
||||
190
loader/src/decompress/tcdecomp.s
Normal file
190
loader/src/decompress/tcdecomp.s
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
|
||||
decompress = decrunch
|
||||
decompsrc = sp
|
||||
|
||||
TC_BLOCK_INTERFACE = 1
|
||||
|
||||
.if (PLATFORM = diskio::platform::COMMODORE_64) | (PLATFORM = diskio::platform::COMMODORE_128)
|
||||
USE_UNINTENDED_OPCODES = 1
|
||||
.else
|
||||
USE_UNINTENDED_OPCODES = 0
|
||||
.endif
|
||||
|
||||
;.export decrunch
|
||||
.if USE_UNINTENDED_OPCODES
|
||||
.define sbx axs
|
||||
.endif
|
||||
|
||||
.if MEM_DECOMP_TO_API
|
||||
dp=decdestlo
|
||||
.else
|
||||
dp=DECOMPVARS + 0 ;4
|
||||
.endif
|
||||
sp=DECOMPVARS + 2 ;6 ; sp must follow dp, cf init code
|
||||
cs=DECOMPVARS + 4 ;8
|
||||
|
||||
|
||||
decrunch:
|
||||
.if TC_BLOCK_INTERFACE = 0
|
||||
stx sp+1
|
||||
.endif
|
||||
|
||||
ldy#2
|
||||
init_loop:
|
||||
.if USE_UNINTENDED_OPCODES
|
||||
stx sp-2,y ;first iter stores sp-low :D
|
||||
.else
|
||||
sta sp-2,y ;first iter stores sp-low :D
|
||||
.endif
|
||||
.if TC_BLOCK_INTERFACE
|
||||
; read three blocks ahead,
|
||||
; - one because literal strings read up to 128 bytes past sp
|
||||
; - two more to absorb up to 256 blocks worth of read 254 bytes/use 256 bytes
|
||||
tya
|
||||
pha
|
||||
jsr tc_getblock
|
||||
pla
|
||||
tay
|
||||
.endif
|
||||
.if USE_UNINTENDED_OPCODES
|
||||
lax(sp),y
|
||||
.else
|
||||
lda(sp),y
|
||||
.endif
|
||||
dey
|
||||
bpl init_loop
|
||||
pha
|
||||
|
||||
.if MEM_DECOMP_TO_API
|
||||
storedadrl = * + 1
|
||||
storedadrh = * + 1
|
||||
lda #0
|
||||
cmp #OPC_STA_ZP
|
||||
beq :+
|
||||
lda dp; override destination address
|
||||
bne *+4
|
||||
dec dp+1
|
||||
dec dp
|
||||
jmp :++
|
||||
: lda sp-2; destination address as stored in header
|
||||
sta dp
|
||||
lda sp-1
|
||||
sta dp+1
|
||||
:
|
||||
.endif
|
||||
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc dp
|
||||
sta dp
|
||||
lda loadaddroffshi
|
||||
adc dp+1
|
||||
sta dp+1
|
||||
.endif
|
||||
|
||||
lda#$02
|
||||
bne update_sp
|
||||
|
||||
literal_run:
|
||||
literal_loop:
|
||||
iny
|
||||
lda(sp),y
|
||||
sta(dp),y
|
||||
dex
|
||||
bmi literal_loop
|
||||
|
||||
tya
|
||||
pha
|
||||
clc
|
||||
increase_dp_by_a_and_sp_by_tos_plus_one:
|
||||
adc dp
|
||||
sta dp
|
||||
bcc :+
|
||||
inc dp+1
|
||||
:
|
||||
pla
|
||||
update_sp:
|
||||
sec
|
||||
adc sp
|
||||
sta sp
|
||||
bcc :+
|
||||
inc sp+1
|
||||
.if TC_BLOCK_INTERFACE
|
||||
jsr tc_getblock
|
||||
.endif
|
||||
:
|
||||
next_command:
|
||||
POLLBLOCK
|
||||
|
||||
ldy#0
|
||||
.if USE_UNINTENDED_OPCODES
|
||||
lax(sp),y
|
||||
.else
|
||||
lda(sp),y
|
||||
tax
|
||||
.endif
|
||||
beq decrunch_done
|
||||
; literal: x = 128+length-1
|
||||
; near copy: a = %11xxxxxx
|
||||
; far copy: a|0xf8 = >(~(offset-1)), x = 8*(length-2) | (some low bits)
|
||||
asl
|
||||
bcc far_copy
|
||||
bpl literal_run
|
||||
|
||||
near_copy:
|
||||
ldx#$07 ; clear high byte of -ve offset. Also ensures copy_loop doesn't loop.
|
||||
.byt $f0 ; beq (not taken) to skip over the iny
|
||||
far_copy:
|
||||
iny
|
||||
; carry is set for near_copy, clear for far_copy
|
||||
|
||||
lda(sp),y ;fetch second byte (or for near copy, refetch first). This is low 8 bits of offset.
|
||||
adc dp
|
||||
sta cs
|
||||
txa
|
||||
ora#$f8
|
||||
adc dp+1
|
||||
sta cs+1
|
||||
.if USE_UNINTENDED_OPCODES = 0
|
||||
txa
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
.endif
|
||||
tya
|
||||
pha ; save opcode length to stack
|
||||
ldy#1
|
||||
lda(cs),y
|
||||
sta(dp),y
|
||||
|
||||
copy_loop:
|
||||
iny
|
||||
lda(cs),y
|
||||
sta(dp),y
|
||||
.if USE_UNINTENDED_OPCODES
|
||||
txa ; spend an extra 2 cycles per byte here to save 10 in the bitfield extraction. A win on average
|
||||
sbx#8
|
||||
bpl copy_loop
|
||||
.else
|
||||
dex
|
||||
bpl copy_loop
|
||||
clc
|
||||
.endif
|
||||
tya
|
||||
bcc increase_dp_by_a_and_sp_by_tos_plus_one ; always taken.
|
||||
|
||||
decrunch_done:
|
||||
pla
|
||||
iny
|
||||
sta(dp),y
|
||||
rts
|
||||
|
||||
.if TC_BLOCK_INTERFACE
|
||||
tc_getblock:
|
||||
GETBLOCK sp+1
|
||||
rts
|
||||
.endif
|
||||
|
||||
edecrunch:
|
||||
392
loader/src/decompress/tsdecomp.s
Normal file
392
loader/src/decompress/tsdecomp.s
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
|
||||
decompsrc = tsget
|
||||
|
||||
decompress = tsdecrunch
|
||||
|
||||
.feature c_comments, leading_dot_in_identifiers
|
||||
|
||||
.define .label
|
||||
|
||||
/*
|
||||
|
||||
decrunch_extreme.asm
|
||||
|
||||
NMOS 6502 decompressor for data stored in TSCrunch format.
|
||||
|
||||
Copyright Antonio Savona 2022.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
.define INPLACE 1 ; Enables inplace decrunching. Use -i switch when crunching.
|
||||
|
||||
.label tsget = DECOMPVARS + 0 ; 2 bytes
|
||||
.label tstemp = DECOMPVARS + 2
|
||||
.label tsput = decdestlo ; 2 bytes
|
||||
.label lzput = DECOMPVARS + 3 ; 2 bytes
|
||||
|
||||
|
||||
.if INPLACE
|
||||
|
||||
.macro TS_DECRUNCH src
|
||||
lda #<src
|
||||
sta.zp tsget
|
||||
lda #>src
|
||||
sta.zp tsget + 1
|
||||
jsr tsdecrunch
|
||||
.endmacro
|
||||
|
||||
.else
|
||||
|
||||
.macro TS_DECRUNCH(src,dst)
|
||||
{
|
||||
lda #<src
|
||||
sta.zp tsget
|
||||
lda #>src
|
||||
sta.zp tsget + 1
|
||||
lda #<dst
|
||||
sta.zp tsput
|
||||
lda #>dst
|
||||
sta.zp tsput + 1
|
||||
jsr tsdecrunch
|
||||
}
|
||||
|
||||
.endif
|
||||
|
||||
|
||||
tsdecrunch:
|
||||
jsr getfirstblock
|
||||
decrunch:
|
||||
|
||||
.if INPLACE
|
||||
;ldy #0
|
||||
dey
|
||||
: iny
|
||||
sta optRun + 1
|
||||
.if PREFER_SPEED_OVER_SIZE
|
||||
ldx #$d0 ; bne opcode
|
||||
and #1
|
||||
bne skp
|
||||
ldx #$29 ; and immediate opcode
|
||||
skp:
|
||||
stx optOdd
|
||||
.endif
|
||||
.if MEM_DECOMP_TO_API
|
||||
storedadrl = * + 1
|
||||
storedadrh = * + 1
|
||||
lda #0
|
||||
cmp #OPC_LDA_ZP
|
||||
lda (tsget),y
|
||||
bcs :+
|
||||
sta tsput , y ; last iteration trashes lzput, with no effect.
|
||||
:
|
||||
cpy #3
|
||||
bne :--
|
||||
.else
|
||||
lda (tsget),y
|
||||
sta tsput , y ; last iteration trashes lzput, with no effect.
|
||||
cpy #3
|
||||
bne :-
|
||||
.endif
|
||||
pha
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc tsput
|
||||
sta tsput
|
||||
lda loadaddroffshi
|
||||
adc tsput + 1
|
||||
sta tsput + 1
|
||||
sec
|
||||
.endif
|
||||
tya
|
||||
ldy #0
|
||||
beq update_getonly
|
||||
.else
|
||||
ldy #0
|
||||
|
||||
lda (tsget),y
|
||||
sta optRun + 1
|
||||
|
||||
ldx #$d0 //bne opcode
|
||||
and #1
|
||||
bne !skp+
|
||||
ldx #$29 //and immediate opcode
|
||||
!skp:
|
||||
stx optOdd
|
||||
|
||||
inc tsget
|
||||
bne entry2
|
||||
inc tsget + 1
|
||||
.endif
|
||||
|
||||
entry2:
|
||||
POLLBLOCK
|
||||
|
||||
lax (tsget),y
|
||||
|
||||
bmi rleorlz
|
||||
|
||||
cmp #$20
|
||||
bcs lz2
|
||||
; literal
|
||||
|
||||
.if INPLACE
|
||||
|
||||
inc tsget
|
||||
beq updatelit_hi
|
||||
return_from_updatelit:
|
||||
and #1
|
||||
bne odd_lit
|
||||
|
||||
ts_delit_loop:
|
||||
|
||||
lda (tsget),y
|
||||
sta (tsput),y
|
||||
iny
|
||||
dex
|
||||
odd_lit:
|
||||
lda (tsget),y
|
||||
sta (tsput),y
|
||||
iny
|
||||
dex
|
||||
|
||||
bne ts_delit_loop
|
||||
|
||||
tya
|
||||
tax
|
||||
; carry is clear
|
||||
ldy #0
|
||||
.else ; not inplace
|
||||
tay
|
||||
|
||||
and #1
|
||||
bne !odd+
|
||||
|
||||
ts_delit_loop:
|
||||
|
||||
lda (tsget),y
|
||||
dey
|
||||
sta (tsput),y
|
||||
!odd:
|
||||
lda (tsget),y
|
||||
dey
|
||||
sta (tsput),y
|
||||
|
||||
bne ts_delit_loop
|
||||
|
||||
txa
|
||||
inx
|
||||
.endif
|
||||
|
||||
updatezp_noclc:
|
||||
adc tsput
|
||||
sta tsput
|
||||
bcs updateput_hi
|
||||
putnoof:
|
||||
txa
|
||||
update_getonly:
|
||||
adc tsget
|
||||
sta tsget
|
||||
bcc entry2
|
||||
jsr getblock
|
||||
bcc entry2
|
||||
|
||||
.if INPLACE
|
||||
updatelit_hi:
|
||||
pha
|
||||
jsr getblock
|
||||
pla
|
||||
tax
|
||||
bcc return_from_updatelit
|
||||
.endif
|
||||
updateput_hi:
|
||||
inc tsput+1
|
||||
clc
|
||||
bcc putnoof
|
||||
|
||||
; LZ2
|
||||
lz2:
|
||||
beq done
|
||||
|
||||
ora #$80
|
||||
adc tsput
|
||||
sta lzput
|
||||
lda tsput + 1
|
||||
sbc #$00
|
||||
sta lzput + 1
|
||||
|
||||
; y already zero
|
||||
lda (lzput),y
|
||||
sta (tsput),y
|
||||
iny
|
||||
lda (lzput),y
|
||||
sta (tsput),y
|
||||
.if PREFER_SPEED_OVER_SIZE
|
||||
tya
|
||||
dey
|
||||
|
||||
adc tsput
|
||||
sta tsput
|
||||
bcs lz2_put_hi
|
||||
skp_lz2:
|
||||
inc tsget
|
||||
bne entry2
|
||||
jsr getblock
|
||||
bcc entry2
|
||||
|
||||
lz2_put_hi:
|
||||
inc tsput + 1
|
||||
bcs skp_lz2
|
||||
.else
|
||||
tya ; y = a = 1.
|
||||
tax ; y = a = x = 1. a + carry = 2
|
||||
dey ; ldy #0
|
||||
|
||||
beq updatezp_noclc
|
||||
.endif
|
||||
rleorlz:
|
||||
|
||||
alr #$7f
|
||||
bcc ts_delz
|
||||
|
||||
; RLE
|
||||
beq zeroRun
|
||||
|
||||
plain:
|
||||
|
||||
ldx #2
|
||||
iny
|
||||
sta tstemp ; number of bytes to de-rle
|
||||
|
||||
lsr ; c = test parity
|
||||
|
||||
lda (tsget),y ; fetch rle byte
|
||||
ldy tstemp
|
||||
runStart:
|
||||
sta (tsput),y
|
||||
|
||||
bcs odd_rle
|
||||
sec
|
||||
|
||||
ts_derle_loop:
|
||||
dey
|
||||
sta (tsput),y
|
||||
odd_rle:
|
||||
|
||||
dey
|
||||
sta (tsput),y
|
||||
|
||||
bne ts_derle_loop
|
||||
|
||||
; update zero page with a = runlen, x = 2 , y = 0
|
||||
lda tstemp
|
||||
bcs updatezp_noclc
|
||||
|
||||
|
||||
done:
|
||||
.if INPLACE
|
||||
pla
|
||||
sta (tsput),y
|
||||
.endif
|
||||
rts
|
||||
|
||||
|
||||
; LZ
|
||||
ts_delz:
|
||||
|
||||
lsr
|
||||
sta lzto + 1
|
||||
|
||||
iny
|
||||
|
||||
lda tsput
|
||||
bcc long
|
||||
|
||||
sbc (tsget),y
|
||||
sta lzput
|
||||
lda tsput+1
|
||||
|
||||
sbc #$00
|
||||
|
||||
ldx #2
|
||||
; lz MUST decrunch forward
|
||||
lz_put:
|
||||
sta lzput+1
|
||||
|
||||
ldy #0
|
||||
|
||||
lda lzto + 1
|
||||
lsr
|
||||
bcs odd_lz
|
||||
|
||||
lda (lzput),y
|
||||
sta (tsput),y
|
||||
ts_delz_loop:
|
||||
iny
|
||||
|
||||
odd_lz:
|
||||
|
||||
lda (lzput),y
|
||||
sta (tsput),y
|
||||
|
||||
iny
|
||||
|
||||
lda (lzput),y
|
||||
sta (tsput),y
|
||||
|
||||
lzto: cpy #0
|
||||
bne ts_delz_loop
|
||||
|
||||
tya
|
||||
|
||||
; update zero page with a = runlen, x = 2, y = 0
|
||||
ldy #0
|
||||
; clc not needed as we have len - 1 in A (from the encoder) and C = 1
|
||||
jmp updatezp_noclc
|
||||
|
||||
zeroRun:
|
||||
optRun: ldy #255
|
||||
.if PREFER_SPEED_OVER_SIZE
|
||||
sta (tsput),y
|
||||
optOdd: bne odd_zero
|
||||
ts_dezero_loop:
|
||||
dey
|
||||
sta (tsput),y
|
||||
odd_zero:
|
||||
dey
|
||||
sta (tsput),y
|
||||
bne ts_dezero_loop
|
||||
|
||||
lda optRun + 1
|
||||
|
||||
ldx #1
|
||||
jmp updatezp_noclc
|
||||
.else
|
||||
sty tstemp
|
||||
tya
|
||||
alr #$01
|
||||
ldx #1
|
||||
bne runStart
|
||||
.endif
|
||||
long:
|
||||
; carry is clear and compensated for from the encoder
|
||||
adc (tsget),y
|
||||
sta lzput
|
||||
iny
|
||||
lax (tsget),y
|
||||
ora #$80
|
||||
adc tsput + 1
|
||||
|
||||
cpx #$80
|
||||
rol lzto + 1
|
||||
ldx #3
|
||||
|
||||
bne lz_put
|
||||
|
||||
getblock:
|
||||
inc tsget + 1
|
||||
getfirstblock:
|
||||
GETBLOCK tsget + 1
|
||||
clc
|
||||
rts
|
||||
672
loader/src/decompress/zx0decomp.s
Normal file
672
loader/src/decompress/zx0decomp.s
Normal file
|
|
@ -0,0 +1,672 @@
|
|||
|
||||
;
|
||||
; (c) Copyright 2021 by Tobias Bindhammer. All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * The name of its author may not be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;
|
||||
|
||||
.FEATURE labels_without_colons, leading_dot_in_identifiers
|
||||
|
||||
.if MEM_DECOMP_TO_API
|
||||
; cannot perform src == dst check when not depacking in-place,
|
||||
; as offsets (arbitrary src - original src) or (arbitrary dst - original dst) are not known,
|
||||
; also cannot copy remaining uncompressed blob of unknown size
|
||||
.error "***** MEM_DECOMP_TO_API is not supported for ZX0. Copy compressed data to original location, then use MEM_DECOMP_API to decompress in-place. *****"
|
||||
.endif
|
||||
|
||||
.if PREFER_SPEED_OVER_SIZE
|
||||
|
||||
; faster but bigger decruncher
|
||||
|
||||
decompsrc = lz_src
|
||||
|
||||
lz_bits = BLOCKINDEX + 1
|
||||
lz_src = DECOMPVARS + 0
|
||||
lz_dst = decdestlo
|
||||
lz_len_hi = DECOMPVARS + 4
|
||||
|
||||
; USE_DALI is defined in resident.s
|
||||
.if USE_DALI
|
||||
.define set_lz_bit_marker ror
|
||||
.define get_lz_bit lsr <lz_bits
|
||||
.else
|
||||
.define set_lz_bit_marker rol
|
||||
.define get_lz_bit asl <lz_bits
|
||||
.endif
|
||||
.define inc_src_ptr jsr lz_next_page ;sets X = 0, so all sane
|
||||
|
||||
;------------------
|
||||
;ELIAS FETCH
|
||||
;------------------
|
||||
.lz_refill_bits
|
||||
tax ;save bits fetched so far
|
||||
lda (lz_src),y ;fetch another lz_bits byte from stream
|
||||
set_lz_bit_marker
|
||||
sta <lz_bits
|
||||
inc <lz_src + 0 ;postponed pointer increment, so no need to save A on next_page call
|
||||
beq .lz_inc_src2
|
||||
.lz_inc_src2_
|
||||
txa ;restore fetched bits, also postponed, so A can be trashed on lz_inc_src above
|
||||
bcs .lz_lend ;last bit fetched?
|
||||
.lz_get_loop
|
||||
get_lz_bit ;fetch payload bit
|
||||
.lz_length_16_
|
||||
rol ;shift in new payload bit
|
||||
bcs .lz_length_16 ;first 1 drops out from lowbyte, need to extend to 16 bit, unfortunatedly this does not work with inverted numbers
|
||||
get_lz_bit ;fetch control bit
|
||||
bcc .lz_get_loop ;need more bits
|
||||
beq .lz_refill_bits ;buffer is empty, fetch new bits
|
||||
.lz_lend ;was the last bit
|
||||
rts
|
||||
.lz_length_16 ;this routine happens very rarely, so we can waste cycles
|
||||
pha ;save so far received lobyte
|
||||
tya ;was lda #$01, but A = 0 + upcoming rol makes this also start with A = 1
|
||||
jsr .lz_length_16_ ;get up to 7 more bits
|
||||
sta <lz_len_hi ;and save hibyte
|
||||
pla ;restore lobyte
|
||||
; bne .lz_not_zero ;was the lobyte zero?
|
||||
; pla ;pull lowbyte of last jsr-call from stack
|
||||
; pha ;restore
|
||||
; ;eor #<.lz_jsr_addr
|
||||
; bmi + ;eof and match case, no need to decrement lz_len_hi
|
||||
; dec <lz_len_hi ;decrement lz_len_hi
|
||||
;+
|
||||
; tya
|
||||
|
||||
bne .lz_not_zero ;was the lobyte zero?
|
||||
dec <lz_len_hi ;yes, so decrement hibyte beforehand to avoid expensive checks later on, except for one case
|
||||
tya ;keep Z = 0, (but not needed in case of eof, the dec also results in 0 there)
|
||||
|
||||
.lz_not_zero
|
||||
rts
|
||||
|
||||
;------------------
|
||||
;DECOMP INIT
|
||||
;------------------
|
||||
decompress
|
||||
;copy over end_pos and lz_dst from stream
|
||||
; ldy #$00 ;needs to be set in any case, also plain decomp enters here
|
||||
ldx #$02
|
||||
.if USE_DALI
|
||||
stx <lz_bits
|
||||
.endif
|
||||
:
|
||||
lda (lz_src),y
|
||||
sta <lz_dst,x
|
||||
inc <lz_src
|
||||
jsr .lz_init
|
||||
dex
|
||||
bpl :-
|
||||
sty .lz_offset_lo + 1 ;initialize offset with $0000
|
||||
sty .lz_offset_hi + 1
|
||||
sty <lz_len_hi ;reset len - XXX TODO could also be cleared upon installer, as the depacker leaves that value clean again
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc <lz_dst
|
||||
sta <lz_dst
|
||||
lda loadaddroffshi
|
||||
adc <lz_dst + 1
|
||||
sta <lz_dst + 1
|
||||
jmp .lz_poll
|
||||
.else
|
||||
bmi .lz_poll; jmp
|
||||
.endif
|
||||
|
||||
;------------------
|
||||
;SELDOM STUFF
|
||||
;------------------
|
||||
.lz_inc_src2
|
||||
inc_src_ptr
|
||||
bne .lz_inc_src2_
|
||||
.lz_inc_src3
|
||||
inc_src_ptr
|
||||
bcs .lz_inc_src3_
|
||||
.lz_dst_inc
|
||||
inc <lz_dst + 1
|
||||
bcs .lz_dst_inc_
|
||||
|
||||
;------------------
|
||||
;SELDOM STUFF
|
||||
;------------------
|
||||
.lz_clc
|
||||
clc
|
||||
bcc .lz_clc_back
|
||||
.lz_cp_page
|
||||
dec <lz_len_hi
|
||||
txa ;much shorter this way. if we recalculate m_src and dst, endcheck also hits in if we end with an multipage match, else maybe buggy?
|
||||
beq .lz_l_page ;if entered from a literal, x == 0
|
||||
tya ;if entered from a match, x is anything between $01 and $ff due to inx stx <lz_dst + 1, except if we would depack to zp?
|
||||
bcs .lz_m_page ;as Y = 0, we can skip the part that does Y = A xor $ff
|
||||
|
||||
;------------------
|
||||
;POLLING
|
||||
;------------------
|
||||
.lz_poll
|
||||
.lz_start_over
|
||||
POLLBLOCK
|
||||
|
||||
;------------------
|
||||
;ENTRY POINT DEPACKER
|
||||
;------------------
|
||||
|
||||
lda #$01 ;we fall through this check on entry and start with literal
|
||||
get_lz_bit
|
||||
bcs .lz_match ;after each match check for another match or literal?
|
||||
|
||||
;------------------
|
||||
;LITERAL
|
||||
;------------------
|
||||
.lz_literal
|
||||
get_lz_bit
|
||||
bcs :++
|
||||
:
|
||||
get_lz_bit ;fetch payload bit
|
||||
rol ;can also moved to front and executed once on start
|
||||
get_lz_bit ;fetch payload bit
|
||||
bcc :-
|
||||
:
|
||||
bne :+
|
||||
.lz_start_depack
|
||||
jsr .lz_refill_bits
|
||||
:
|
||||
tax
|
||||
.lz_l_page
|
||||
.lz_cp_lit ;XXX TODO copy with Y += 1 but have lz_src + 0 eor #$ff in x and countdown x, so that lz_src + 1 can be incremented in time?
|
||||
lda (lz_src),y ;/!\ Need to copy this way, or we run into danger to copy from an area that is yet blocked by barrier, this totally sucks, loading in order reveals that
|
||||
sta (lz_dst),y
|
||||
|
||||
inc <lz_src + 0
|
||||
beq .lz_inc_src3
|
||||
.lz_inc_src3_
|
||||
inc <lz_dst + 0
|
||||
beq .lz_dst_inc
|
||||
.lz_dst_inc_
|
||||
dex
|
||||
bne .lz_cp_lit
|
||||
;XXX TODO we could also just manipulate a branch and make it go to either page handling or fall through? enable branch if 16 bits are fetched and lz_len > 0? dop or bcs to disable and enable, 80 or b0
|
||||
lda <lz_len_hi ;more pages to copy?
|
||||
bne .lz_cp_page ;happens very seldom
|
||||
|
||||
;------------------
|
||||
;NEW OR OLD OFFSET
|
||||
;------------------
|
||||
;XXX TODO fetch length first and then decide if literal, match, repeat? But brings our checks for last bit to the end? need to check then on typebit? therefore entry for fetch is straight?
|
||||
;in case of type bit == 0 we can always receive length (not length - 1), can this used for an optimization? can we fetch length beforehand? and then fetch offset? would make length fetch simpler? place some other bit with offset?
|
||||
rol ;was A = 0, C = 1 -> A = 1 with rol, but not if we copy literal this way
|
||||
get_lz_bit
|
||||
bcs .lz_match ;either match with new offset or old offset
|
||||
|
||||
;------------------
|
||||
;REPEAT LAST OFFSET
|
||||
;------------------
|
||||
.lz_repeat
|
||||
get_lz_bit
|
||||
bcs :++
|
||||
:
|
||||
get_lz_bit ;fetch payload bit
|
||||
rol ;can also moved to front and executed once on start
|
||||
get_lz_bit ;cheaper with 2 branches, as initial branch to .lz_literal therefore is removed
|
||||
bcc :-
|
||||
:
|
||||
bne :+
|
||||
jsr .lz_refill_bits ;fetch more bits
|
||||
beq .lz_m_page ;XXX TODO sec after sbc #1 is also sufficient, but slower
|
||||
:
|
||||
sbc #$01 ;subtract 1, will be added again on adc as C = 1
|
||||
.lz_match_big ;we enter with length - 1 here from normal match
|
||||
eor #$ff
|
||||
tay
|
||||
.lz_m_page
|
||||
eor #$ff ;restore A
|
||||
|
||||
adc <lz_dst + 0 ;add length
|
||||
sta <lz_dst + 0
|
||||
bcs .lz_clc ;/!\ branch happens very seldom, if so, clear carry
|
||||
dec <lz_dst + 1 ;subtract one more in this case
|
||||
.lz_clc_back
|
||||
.lz_offset_lo sbc #$00 ;carry is cleared, subtract (offset + 1)
|
||||
sta .lz_msrcr + 0
|
||||
lax <lz_dst + 1
|
||||
.lz_offset_hi sbc #$00
|
||||
sta .lz_msrcr + 1
|
||||
.lz_cp_match ;XXX TODO if repeated offset: add literal size to .lz_msrcr and done?
|
||||
.lz_msrcr = * + 1
|
||||
lda $beef,y
|
||||
sta (lz_dst),y
|
||||
iny
|
||||
bne .lz_cp_match
|
||||
inx
|
||||
stx <lz_dst + 1 ;cheaper to get lz_dst + 1 into x than lz_dst + 0 for upcoming compare
|
||||
|
||||
lda <lz_len_hi ;check for more loop runs
|
||||
.if LOAD_TO_RAM_UNDER_IO | LOAD_VIA_KERNAL_FALLBACK
|
||||
beq :+
|
||||
jmp .lz_cp_page ;do more page runs? Yes? Fall through
|
||||
:
|
||||
.else
|
||||
bne .lz_cp_page ;do more page runs? Yes? Fall through
|
||||
.endif
|
||||
.lz_check_poll
|
||||
cpx <lz_src + 1 ;check for end condition when depacking inplace, lz_dst + 0 still in X
|
||||
.if LOAD_TO_RAM_UNDER_IO | LOAD_VIA_KERNAL_FALLBACK
|
||||
bne :+
|
||||
|
||||
lda <lz_dst + 0
|
||||
eor <lz_src + 0
|
||||
beq lz_next_page
|
||||
: jmp .lz_start_over
|
||||
.else
|
||||
bne .lz_start_over
|
||||
|
||||
lda <lz_dst + 0
|
||||
eor <lz_src + 0
|
||||
bne .lz_start_over
|
||||
beq lz_next_page
|
||||
.endif
|
||||
;XXX TODO, save one byte above and the beq lz_next_page can be omitted and lz_next_page copied here again
|
||||
;jmp .ld_load_raw ;but should be able to skip fetch, so does not work this way
|
||||
;top ;if lz_src + 1 gets incremented, the barrier check hits in even later, so at least one block is loaded, if it was $ff, we at least load the last block @ $ffxx, it must be the last block being loaded anyway
|
||||
;as last block is forced, we would always wait for last block to be loaded if we enter this loop, no matter how :-)
|
||||
;------------------
|
||||
;MATCH
|
||||
;------------------
|
||||
:
|
||||
get_lz_bit ;fetch payload bit
|
||||
rol ;add bit to number
|
||||
.lz_match
|
||||
get_lz_bit ;fetch control bit
|
||||
bcc :- ;not yet done, fetch more bits
|
||||
|
||||
bne :+ ;last bit or bitbuffer empty? fetched 1 to 4 bits now
|
||||
jsr .lz_refill_bits ;refill bitbuffer
|
||||
beq .lz_eof ;so offset was $100 as lowbyte is $00, only here 4-8 bits are fetched
|
||||
:
|
||||
sbc #$01 ;subtract 1, elias numbers range from 1..256, we need 0..255
|
||||
lsr ;set bit 15 to 0 while shifting hibyte
|
||||
sta .lz_offset_hi + 1 ;hibyte of offset
|
||||
|
||||
lda (lz_src),y ;fetch another byte directly, same as refill_bits...
|
||||
ror ;and shift -> first bit for lenth is in carry, and we have %0xxxxxxx xxxxxxxx as offset
|
||||
sta .lz_offset_lo + 1 ;lobyte of offset
|
||||
|
||||
inc <lz_src + 0 ;postponed, so no need to save A on next_page call
|
||||
beq .lz_inc_src1
|
||||
.lz_inc_src1_
|
||||
lda #$01 ;fetch new number, start with 1
|
||||
bcs .lz_match_big ;length = 1, do it the very short way
|
||||
:
|
||||
get_lz_bit ;fetch more bits
|
||||
rol
|
||||
get_lz_bit
|
||||
bcc :-
|
||||
bne .lz_match_big
|
||||
jsr .lz_refill_bits ;fetch remaining bits
|
||||
;.lz_jsr_addr = * - 1
|
||||
; bcs .lz_match_big ;lobyte != 0?
|
||||
bne .lz_match_big ;lobyte != 0?
|
||||
|
||||
;------------------
|
||||
;SELDOM STUFF
|
||||
;------------------
|
||||
|
||||
inc <lz_len_hi ;need to correct <lz_len_hi
|
||||
bcs .lz_match_big ;and enter match copy loop
|
||||
.lz_inc_src1
|
||||
inc_src_ptr
|
||||
bne .lz_inc_src1_
|
||||
|
||||
;------------------
|
||||
;NEXT PAGE IN STREAM
|
||||
;------------------
|
||||
.lz_init
|
||||
bne .lz_next_page_
|
||||
lz_next_page
|
||||
inc <lz_src + 1
|
||||
.lz_next_page_
|
||||
php
|
||||
txa
|
||||
pha
|
||||
GETBLOCK <lz_src + 1
|
||||
pla
|
||||
tax
|
||||
plp
|
||||
.lz_eof
|
||||
rts
|
||||
|
||||
;XXX TODO
|
||||
;decide upon 2 bits with bit <lz_bits? bmi + bvs + bvc? bpl/bmi decides if repeat or not, bvs = length 2/check for new bits and redecide, other lengths do not need to check, this can alos be used on other occasions?
|
||||
;do a jmp ($00xx) to determine branch?
|
||||
|
||||
.else
|
||||
|
||||
decompsrc = .lz_src
|
||||
|
||||
OFFSET_OPT = 0; +8
|
||||
|
||||
.lz_bits = BLOCKINDEX + 1
|
||||
.lz_src = DECOMPVARS + 0
|
||||
.lz_dst = decdestlo
|
||||
.if OFFSET_OPT
|
||||
.else
|
||||
.lz_offset = DECOMPVARS + 2
|
||||
.endif
|
||||
.lz_len_hi = DECOMPVARS + 4
|
||||
|
||||
; USE_DALI is defined in resident.s
|
||||
.if USE_DALI
|
||||
.define rot ror
|
||||
.define shf lsr
|
||||
.else
|
||||
.define rot rol
|
||||
.define shf asl
|
||||
.endif
|
||||
|
||||
;------------------
|
||||
;SELDOM STUFF
|
||||
;------------------
|
||||
.lz_l_page
|
||||
.lz_dcp
|
||||
dec <.lz_len_hi
|
||||
bcs .lz_cp_lit
|
||||
sec
|
||||
bcs .lz_match_big
|
||||
|
||||
;------------------
|
||||
;POINTER HANDLING LITERAL COPY
|
||||
;------------------
|
||||
.lz_dst_inc
|
||||
inc <.lz_dst + 1
|
||||
bcs .lz_dst_inc_
|
||||
.lz_src_inc
|
||||
jsr .lz_next_page ;sets X = 0, so all sane
|
||||
bcs .lz_src_inc_
|
||||
|
||||
decompress
|
||||
;copy over end_pos and lz_dst from stream
|
||||
ldx #2
|
||||
.if USE_DALI
|
||||
stx <.lz_bits
|
||||
.endif
|
||||
:
|
||||
lda (.lz_src),y ;copy over first two bytes
|
||||
sta <.lz_dst,x
|
||||
inc <.lz_src + 0
|
||||
jsr .lz_init
|
||||
.if OFFSET_OPT
|
||||
.else
|
||||
sty .lz_offset,x; reset offset and length-hi
|
||||
.endif
|
||||
dex
|
||||
bpl :-
|
||||
.if LOADCOMPD_TO
|
||||
clc
|
||||
lda loadaddroffslo
|
||||
adc <.lz_dst
|
||||
sta <.lz_dst
|
||||
lda loadaddroffshi
|
||||
adc <.lz_dst + 1
|
||||
sta <.lz_dst + 1
|
||||
.endif
|
||||
|
||||
.if OFFSET_OPT
|
||||
sty .lz_offset_lo + 1 ;initialize offset with $0000
|
||||
sty .lz_offset_hi + 1
|
||||
sty <.lz_len_hi ;reset len - XXX TODO could also be cleared upon installer, as the depacker leaves that value clean again
|
||||
.endif
|
||||
;start with an empty lz_bits, first shf <.lz_bits leads to literal this way and bits are refilled upon next shift
|
||||
.if USE_DALI
|
||||
.elseif LOAD_VIA_KERNAL_FALLBACK | MEM_DECOMP_API
|
||||
lda #$40
|
||||
sta <.lz_bits
|
||||
.endif
|
||||
|
||||
;------------------
|
||||
;POLLING
|
||||
;------------------
|
||||
.lz_start_over POLLBLOCK
|
||||
|
||||
;------------------
|
||||
;LITERAL
|
||||
;------------------
|
||||
|
||||
lda #$01 ;we fall through this check on entry and start with literal
|
||||
shf <.lz_bits
|
||||
bcs .lz_match ;after each match check for another match or literal?
|
||||
.lz_literal
|
||||
jsr .lz_length
|
||||
tax
|
||||
beq .lz_l_page ;happens very seldom, so let's do that with lz_l_page that also decrements lz_len_hi, it returns on c = 1, what is always true after jsr .lz_length
|
||||
.lz_cp_lit
|
||||
lda (.lz_src),y ;Need to copy this way, or wie copy from area that is blocked by barrier
|
||||
sta (.lz_dst),y
|
||||
|
||||
inc <.lz_src + 0
|
||||
beq .lz_src_inc
|
||||
.lz_src_inc_
|
||||
inc <.lz_dst + 0
|
||||
beq .lz_dst_inc
|
||||
.lz_dst_inc_
|
||||
dex
|
||||
bne .lz_cp_lit
|
||||
|
||||
lda <.lz_len_hi ;more pages to copy?
|
||||
bne .lz_l_page ;happens very seldom
|
||||
|
||||
;------------------
|
||||
;NEW OR OLD OFFSET
|
||||
;------------------
|
||||
;in case of type bit == 0 we can always receive length (not length - 1), can this used for an optimization? can we fetch length beforehand? and then fetch offset? would make length fetch simpler? place some other bit with offset?
|
||||
rol ;A = 0, C = 1 -> A = 1
|
||||
shf <.lz_bits
|
||||
;rol
|
||||
;bne .lz_match
|
||||
;else A = 0
|
||||
;but only for lowbyte?!
|
||||
bcs .lz_match ;either match with new offset or old offset
|
||||
|
||||
;------------------
|
||||
;DO MATCH
|
||||
;------------------
|
||||
.lz_repeat
|
||||
jsr .lz_length
|
||||
sbc #$01
|
||||
bcc .lz_dcp ;fix highbyte of length in case and set carry again (a = $ff -> compare delivers carry = 1)
|
||||
;sec ;XXX TODO in fact we could save on the sbc #$01 as the sec and adc later on corrects that again, but y would turn out one too less
|
||||
.lz_match_big ;we enter with length - 1 here from normal match
|
||||
eor #$ff
|
||||
tay
|
||||
;XXX TODO save on eor #$ff and do sbc lz_dst + 0?
|
||||
eor #$ff ;restore A
|
||||
.lz_match_len2 ;entry from new_offset handling
|
||||
adc <.lz_dst + 0
|
||||
sta <.lz_dst + 0
|
||||
tax ;remember for later end check, cheaper this way
|
||||
bcs .lz_clc ;/!\ branch happens very seldom, if so, clear carry
|
||||
dec <.lz_dst + 1 ;subtract one more in this case
|
||||
.lz_clc_back
|
||||
.if OFFSET_OPT
|
||||
.lz_offset_lo sbc #$00 ;carry is cleared, subtract (offset + 1) in fact we could use sbx here, but would not respect carry, but a and x are same, but need x later anyway for other purpose
|
||||
.else
|
||||
sbc <.lz_offset
|
||||
.endif
|
||||
sta .lz_msrcr + 0
|
||||
lda <.lz_dst + 1
|
||||
.if OFFSET_OPT
|
||||
.lz_offset_hi sbc #$00
|
||||
.else
|
||||
sbc <.lz_offset + 1
|
||||
.endif
|
||||
sta .lz_msrcr + 1
|
||||
; ;XXX TODO would have dst + 0 and + 1 in X and A here, of any use?
|
||||
.lz_cp_match
|
||||
;XXX TODO if repeated offset: add literal size to .lz_msrcr and done?
|
||||
.lz_msrcr = * + 1
|
||||
lda $beef,y
|
||||
sta (.lz_dst),y
|
||||
iny
|
||||
bne .lz_cp_match
|
||||
inc <.lz_dst + 1
|
||||
|
||||
lda <.lz_len_hi ;check for more loop runs
|
||||
bne .lz_m_page ;do more page runs? Yes? Fall through
|
||||
.lz_check_poll
|
||||
cpx <.lz_src + 0 ;check for end condition when depacking inplace, .lz_dst + 0 still in X
|
||||
.lz_skip_poll bne .lz_start_over ;-> can be changed to .lz_poll, depending on decomp/loadcomp
|
||||
|
||||
lda <.lz_dst + 1
|
||||
sbc <.lz_src + 1
|
||||
bne .lz_start_over
|
||||
|
||||
;jmp .ld_load_raw ;but should be able to skip fetch, so does not work this way
|
||||
;top ;if lz_src + 1 gets incremented, the barrier check hits in even later, so at least one block is loaded, if it was $ff, we at least load the last block @ $ffxx, it must be the last block being loaded anyway
|
||||
;as last block is forced, we would always wait for last block to be loaded if we enter this loop, no matter how :-)
|
||||
|
||||
;------------------
|
||||
;NEXT PAGE IN STREAM
|
||||
;------------------
|
||||
.lz_init
|
||||
bne :+
|
||||
.lz_next_page
|
||||
inc <.lz_src + 1
|
||||
:
|
||||
.if LOAD_TO_RAM_UNDER_IO
|
||||
jmp getblock
|
||||
.else
|
||||
php
|
||||
txa
|
||||
pha
|
||||
GETBLOCK <.lz_src + 1
|
||||
pla
|
||||
tax
|
||||
plp
|
||||
rts
|
||||
.endif
|
||||
;------------------
|
||||
;FETCH A NEW OFFSET
|
||||
;------------------
|
||||
: ;lz_length as inline
|
||||
shf <.lz_bits ;fetch payload bit
|
||||
rol ;can also moved to front and executed once on start
|
||||
.lz_match
|
||||
shf <.lz_bits
|
||||
bcc :-
|
||||
|
||||
bne :+
|
||||
jsr .lz_refill_bits
|
||||
:
|
||||
sbc #$01 ;XXX TODO can be omitted if just endposition is checked, but 0 does not exist as value?
|
||||
bcc .lz_eof ;underflow. must have been 0
|
||||
|
||||
lsr
|
||||
.if OFFSET_OPT
|
||||
sta .lz_offset_hi + 1 ;hibyte of offset
|
||||
.else
|
||||
sta .lz_offset + 1 ;hibyte of offset
|
||||
.endif
|
||||
lda (.lz_src),y ;fetch another byte directly
|
||||
ror
|
||||
.if OFFSET_OPT
|
||||
sta .lz_offset_lo + 1
|
||||
.else
|
||||
sta .lz_offset
|
||||
.endif
|
||||
inc <.lz_src + 0 ;postponed, so no need to save A on next_page call
|
||||
bne :+
|
||||
jsr .lz_next_page ;preserves carry, all sane
|
||||
:
|
||||
lda #$01
|
||||
ldy #$fe
|
||||
bcs .lz_match_len2 ;length = 1 ^ $ff, do it the very short way :-)
|
||||
:
|
||||
shf <.lz_bits ;fetch first payload bit
|
||||
;XXX TODO we could check bit 7 before further shf?
|
||||
rol ;can also moved to front and executed once on start
|
||||
shf <.lz_bits
|
||||
bcc :-
|
||||
bne .lz_match_big
|
||||
ldy #$00 ;only now y = 0 is needed
|
||||
jsr .lz_refill_bits ;fetch remaining bits
|
||||
; bcs .lz_match_big
|
||||
jmp .lz_match_big
|
||||
|
||||
;------------------
|
||||
;SELDOM STUFF
|
||||
;------------------
|
||||
.lz_clc
|
||||
clc
|
||||
bcc .lz_clc_back
|
||||
.lz_m_page
|
||||
dec <.lz_len_hi
|
||||
inc .lz_msrcr + 1 ;XXX TODO only needed if more pages follow
|
||||
bne .lz_cp_match
|
||||
|
||||
;------------------
|
||||
;ELIAS FETCH
|
||||
;------------------
|
||||
.lz_refill_bits
|
||||
tax
|
||||
lda (.lz_src),y
|
||||
rot
|
||||
sta <.lz_bits
|
||||
inc <.lz_src + 0 ;postponed, so no need to save A on next_page call
|
||||
bne :+ ;XXX TODO if we would prefer beq, 0,2% saving
|
||||
jsr .lz_next_page ;preserves carry and A, clears X, Y, all sane
|
||||
:
|
||||
txa
|
||||
bcs .lz_lend
|
||||
|
||||
;lda #$00
|
||||
;slo <.lz_bits
|
||||
.lz_get_loop
|
||||
shf <.lz_bits ;fetch payload bit
|
||||
.lz_length_16_
|
||||
rol ;can also moved to front and executed once on start
|
||||
bcs .lz_length_16 ;first 1 drops out from lowbyte, need to extend to 16 bit, unfortunatedly this does not work with inverted numbers
|
||||
.lz_length
|
||||
shf <.lz_bits
|
||||
|
||||
bcc .lz_get_loop
|
||||
beq .lz_refill_bits
|
||||
.lz_lend
|
||||
.lz_eof
|
||||
rts
|
||||
.lz_length_16 ;happens very rarely
|
||||
pha ;save LSB
|
||||
tya ;was lda #$01, but A = 0 + rol makes this also start with MSB = 1
|
||||
jsr .lz_length_16_ ;get up to 7 more bits
|
||||
sta <.lz_len_hi ;save MSB
|
||||
pla ;restore LSB
|
||||
rts
|
||||
|
||||
.if LOAD_TO_RAM_UNDER_IO
|
||||
getblock php
|
||||
txa
|
||||
pha
|
||||
GETBLOCK <.lz_src + 1
|
||||
pla
|
||||
tax
|
||||
plp
|
||||
rts
|
||||
.endif
|
||||
|
||||
.endif
|
||||
527
loader/src/drives/drivecode-common.inc
Normal file
527
loader/src/drives/drivecode-common.inc
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
|
||||
.ifndef _DRIVECODE_COMMON_INC_
|
||||
_DRIVECODE_COMMON_INC_ = 1
|
||||
|
||||
MIN_DEVICE_NO = 8 ; these two settings define the device number range when scanning for devices in install.s,
|
||||
MAX_DEVICE_NO = 30 ; devices beyond this range will not be recognized or useable
|
||||
|
||||
; 1541/41-C/41-II/41U/70/71/71CR
|
||||
MINSTEPSPEED = $18 ; min. R/W head stepping speed
|
||||
MAXSTEPSPEED = $10 ; max. R/W head stepping speed
|
||||
STEPPERACC = $0c ; R/W head stepping acceleration, smaller is slower acceleration
|
||||
SINGLESTEPSPEED = $0c ; time between two consecutive half-track steps for a single-track step
|
||||
|
||||
.macro ENABLE_WATCHDOG
|
||||
.if ::DISABLE_WATCHDOG
|
||||
sei
|
||||
.else
|
||||
cli
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
.macro DRIVEGETBYTE drivetype, comparelbl, nozeroes
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
.local OFFSET
|
||||
.local getbit
|
||||
|
||||
; must not clobber x
|
||||
|
||||
.if .paramcount < 3
|
||||
OFFSET = 0
|
||||
|
||||
ldy VIA1_PRB + OFFSET
|
||||
.else
|
||||
OFFSET = 16
|
||||
.endif
|
||||
|
||||
lda #%10000000
|
||||
getbit: cpy VIA1_PRB + OFFSET
|
||||
beq getbit
|
||||
ldy VIA1_PRB + OFFSET
|
||||
comparelbl: cpy #ATN_IN | ATNA_OUT | CLK_IN
|
||||
ror
|
||||
bcc getbit
|
||||
|
||||
.assert .hibyte(*) = .hibyte(getbit), error, "***** Page boundary crossing in getbyte loop, fatal cycle loss. *****"
|
||||
.else
|
||||
.local getbit
|
||||
.local waitbit
|
||||
|
||||
lda #%10000000
|
||||
getbit: pha
|
||||
lda CIA_PRB
|
||||
waitbit: cmp CIA_PRB
|
||||
beq waitbit
|
||||
lda CIA_PRB
|
||||
and #CLK_IN
|
||||
cmp #CLK_IN
|
||||
pla
|
||||
ror
|
||||
bcc getbit
|
||||
|
||||
.assert .hibyte(*) = .hibyte(getbit), error, "***** Page boundary crossing in getbyte loop, fatal cycle loss. *****"
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
.macro DRIVESENDBYTE drivetype, sendvalue
|
||||
.local sendbit
|
||||
.local waitbit
|
||||
|
||||
sta sendvalue
|
||||
ldy #8
|
||||
sendbit: asl sendvalue
|
||||
lda #0
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
adc #ATNA_OUT | DATA_IN
|
||||
sta VIA1_PRB
|
||||
lda VIA1_PRB
|
||||
waitbit: cmp VIA1_PRB
|
||||
.else
|
||||
adc #DATA_IN
|
||||
sta CIA_PRB
|
||||
lda CIA_PRB
|
||||
waitbit: cmp CIA_PRB
|
||||
.endif
|
||||
beq waitbit
|
||||
dey
|
||||
bne sendbit
|
||||
.endmacro
|
||||
|
||||
.macro GET_FILENAME drivetype
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
;ldx #0
|
||||
.if .xmatch (drivetype, 1571)
|
||||
lda #ATNA_OUT; ATNA_OUT set, CLK_OUT and DATA_OUT clear: drive is ready
|
||||
sta (V1B,x); VIA1_PRB
|
||||
.endif
|
||||
getfilenam:
|
||||
.if .xmatch (drivetype, 1541)
|
||||
inx
|
||||
getbytewdog41 = getbytewdg
|
||||
getbyterts41 = getbyterts
|
||||
getbytewdg: lda #$f5
|
||||
sta VIA1_PRB; ATNA_OUT set, CLK_OUT and DATA_OUT clear: drive is ready
|
||||
sta TIMER; reset watchdog time-out
|
||||
ENABLE_WATCHDOG
|
||||
getbyte41 = getbyte
|
||||
getbyte: DRIVEGETBYTE 1541, getbytecmp41
|
||||
getbyterts: sta a:FILENAME - 1,x
|
||||
.else
|
||||
inx
|
||||
jsr getbytewdg
|
||||
sta .lobyte(FILENAME - 1),x
|
||||
.endif
|
||||
.else; 1581
|
||||
ldx #0
|
||||
stx CIA_PRB; CLK_OUT and DATA_OUT clear: drive is ready
|
||||
getfilenam: inx
|
||||
jsr getbyte
|
||||
sta filename - 1,x
|
||||
.endif
|
||||
bne getfilenam
|
||||
|
||||
sei; disable watchdog
|
||||
cpx #16 + 3
|
||||
.if .xmatch (drivetype, 1541)
|
||||
bcs getcustom
|
||||
.else
|
||||
bcc :+
|
||||
jmp getcustom
|
||||
:
|
||||
.endif
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
.if .xmatch (drivetype, 1541)
|
||||
dec VIA1_PRB; %1xy10000 -> %1xy01111: drive busy, set CLK_OUT and DATA_OUT
|
||||
.else
|
||||
lda #ERR | ATNA_OUT | CLK_OUT | DATA_OUT; drive busy
|
||||
sta VIA1_PRB
|
||||
sta ERRORCOUNT; reset, as spinning up the motor would yield errors
|
||||
.endif
|
||||
.else
|
||||
lda #CLK_OUT | DATA_OUT; drive busy
|
||||
sta CIA_PRB
|
||||
.endif
|
||||
.if .xmatch (drivetype, 1571)
|
||||
inc prpnxtfjmp; OPC_JMP_ABS -> OPC_EOR_ABS, disable block caching: do not jump to prpdnxtfil (idleloop) after fetching the file's first block
|
||||
.endif
|
||||
: dex ; if zero-length filename,
|
||||
beq loadnextfile ; use hash values of next file
|
||||
cpx #FILENAME_MAXLENGTH + 1
|
||||
bcs :-
|
||||
findfile: sec
|
||||
jsr gethashval
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
setnextfile:
|
||||
.endif
|
||||
sta FILENAMEHASHLO
|
||||
sty FILENAMEHASHHI
|
||||
loadnextfile:
|
||||
.endmacro; GET_FILENAME drivetype
|
||||
|
||||
; matches against hash of filename in FILENAMEHASHLO/HI
|
||||
|
||||
.macro FIND_FILE drivetype
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
chknewdisk:
|
||||
.if .xmatch (drivetype, 1541)
|
||||
lda #$fc
|
||||
sta CYCLESTARTENDSECTOR
|
||||
ldx NUMFILES
|
||||
bpl findloop
|
||||
|
||||
; a new disk has been inserted
|
||||
sta DIRBLOCKPOS
|
||||
jsr getblkbam; store ID, sector link sanity check
|
||||
bcc chknewdisk
|
||||
jsr checkchg
|
||||
lda #1; first dir sector
|
||||
.else
|
||||
lda #0; BAM sector
|
||||
sta CYCLESTARTENDSECTOR
|
||||
ldx NUMFILES
|
||||
bpl findloop
|
||||
|
||||
; a new disk has been inserted
|
||||
;lda #0; BAM sector
|
||||
sta DIRBLOCKPOS
|
||||
|
||||
ldx #.lobyte(storeid - (idswitch + 2))
|
||||
jsr getblkstid; store ID, sector link sanity check
|
||||
bcs chknewdisk
|
||||
jsr checkchg
|
||||
lda #1; first dir sector
|
||||
|
||||
; set seek boundaries according to number of disk sides
|
||||
ldx #MAXTRACK71 + 1
|
||||
ldy #NUMTRACKS_A
|
||||
bit BLOCKBUFFER71 + TWOSIDEDOFFSET
|
||||
bmi :+
|
||||
ldx #NUMTRACKS_SINGLESIDED + 1
|
||||
ldy #NUMTRACKS_SINGLESIDED
|
||||
: stx MAXTRACK
|
||||
sty MAXTRACK_A
|
||||
.endif
|
||||
|
||||
;lda LINKSECTOR
|
||||
.else; 1581
|
||||
inc prpnxtfjmp; OPC_JMP_ABS -> OPC_EOR_ABS, do not jump to after prepare-next-file routine
|
||||
|
||||
prpnxtfile: lda NUMFILES
|
||||
bmi newdisk
|
||||
diskchangd: lda #$00
|
||||
bne newdisk
|
||||
jmp samedisk
|
||||
|
||||
newdisk: ; a new disk has been inserted
|
||||
jsr getdirtrk
|
||||
ldy #$00
|
||||
sty diskchangd + 1
|
||||
sty CYCLESTARTENDTRACK
|
||||
sty CYCLESTARTENDSECTOR
|
||||
jsr getblock81
|
||||
bcs newdisk
|
||||
|
||||
;lda LINKTRACK
|
||||
;ldx LOADEDSECTOR; $00
|
||||
;ldy LINKSECTOR
|
||||
sty FIRSTDIRSECTOR
|
||||
.endif; 1581
|
||||
|
||||
; directory cycling: fill the directory buffer with the next file entries,
|
||||
; this is also executed upon file not found in the currently buffered directory segment
|
||||
; (with accu containing NEXTDIRBLOCKSECTOR's value)
|
||||
nextdirseg:
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
ldy #$ff
|
||||
.else
|
||||
ldx #$ff
|
||||
.endif
|
||||
; file not found (yet)
|
||||
.if .xmatch (drivetype, 1541)
|
||||
ldx CYCLESTARTENDSECTOR
|
||||
beq filenotfnd; branch if cycle complete with z = 0 and y = $ff = diskio::status::FILE_NOT_FOUND
|
||||
.else; !1541
|
||||
bit CYCLESTARTENDSECTOR
|
||||
bpl :+ ; branch if cycle not complete
|
||||
sec
|
||||
jmp filenotfnd
|
||||
:
|
||||
.endif; !1541
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
sty NUMFILES
|
||||
|
||||
.if .xmatch (drivetype, 1541)
|
||||
nextdirsct: ; a = sector
|
||||
jsr getblkdir; compare ID, sector link sanity check
|
||||
bcc chknewdisk
|
||||
;lda LINKSECTOR41
|
||||
;ldx LOADEDSECTOR
|
||||
tay
|
||||
bpl :+; branch if not wrapping to first dir block
|
||||
lda #1; wrap around to first dir sector
|
||||
: sta NEXTDIRBLOCKSECTOR
|
||||
.else; 1571
|
||||
SKIPWORD; do not set CYCLESTARTENDSECTOR
|
||||
dircycle: sta CYCLESTARTENDSECTOR
|
||||
nextdirsct: ; a = sector
|
||||
jsr getblkchid; compare ID, sector link sanity check
|
||||
bcs chknewdisk
|
||||
|
||||
;lda LINKSECTOR
|
||||
;ldy LINKTRACK
|
||||
;cpy CURTRACK
|
||||
beq :+; branch if not wrapping to first dir block
|
||||
lda #1; wrap around to first dir sector
|
||||
: sta NEXTDIRBLOCKSECTOR
|
||||
.endif
|
||||
.else; 1581
|
||||
stx NUMFILES
|
||||
|
||||
nextdirsct: ; a = track
|
||||
; y = sector
|
||||
sta CURRDIRBLOCKTRACK
|
||||
jsr getblock81
|
||||
bcs newdisk; start over on error
|
||||
;ldy LINKSECTOR
|
||||
;lda LINKTRACK
|
||||
bne :+; branch if not wrapping to first dir block
|
||||
jsr getdirtrk
|
||||
ldy FIRSTDIRSECTOR
|
||||
: sta NEXTDIRBLOCKTRACK
|
||||
sty NEXTDIRBLOCKSECTOR
|
||||
|
||||
ldy #0
|
||||
.endif; 1581
|
||||
|
||||
getdirloop:
|
||||
.if .xmatch (drivetype, 1541)
|
||||
ldy DIRBLOCKPOS
|
||||
jsr sertorawr; get file's start track
|
||||
beq notafile; skip non-files denoted by track 0
|
||||
cmp #MAXTRACK41 + 1
|
||||
bcs notafile; or files with invalid start tracks
|
||||
inc NUMFILES
|
||||
ldx NUMFILES
|
||||
sta DIRTRACKS,x
|
||||
jsr sertorawd; get file's start sector
|
||||
sta DIRSECTORS,x
|
||||
lda (BLP),y; number of file blocks (low-byte)
|
||||
jsr sertoraw41
|
||||
sta NUMBLOCKS,x
|
||||
.elseif (.xmatch (drivetype, 1571))
|
||||
ldy DIRBLOCKPOS
|
||||
lda BLOCKBUFFER + 3 + TRACKOFFSET,y; get file's start track
|
||||
beq notafile; skip non-files denoted by track 0
|
||||
cmp MAXTRACK
|
||||
bcs notafile; or files with invalid start tracks
|
||||
inc NUMFILES
|
||||
ldx NUMFILES
|
||||
sta .lobyte(DIRTRACKS),x
|
||||
lda BLOCKBUFFER + 3 + SECTOROFFSET,y; get file's start sector
|
||||
sta .lobyte(DIRSECTORS),x
|
||||
lda BLOCKBUFFER + BLOCKSOFFSET,y
|
||||
sta .lobyte(NUMBLOCKS),x
|
||||
.else; 1581
|
||||
lda BLOCKBUFFER + 3 + TRACKOFFSET,y; get file's start track
|
||||
beq notafile; skip non-files denoted by track 0
|
||||
inc NUMFILES
|
||||
ldx NUMFILES
|
||||
sta DIRTRACKS,x
|
||||
lda BLOCKBUFFER + 3 + SECTOROFFSET,y; get file's start sector
|
||||
sta DIRSECTORS,x
|
||||
tya
|
||||
pha
|
||||
.endif; 1581
|
||||
ldx #0
|
||||
jsr fnamehash
|
||||
ldx NUMFILES; restore x
|
||||
sta FILENAMEHASHVALSLO,x
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
sty FILENAMEHASHVALSHI,x
|
||||
.else
|
||||
tya
|
||||
sta FILENAMEHASHVALSHI,x
|
||||
pla
|
||||
tay
|
||||
.endif
|
||||
; advance to next file or quit loop
|
||||
cpx #DIRBUFFSIZE - 1
|
||||
bcs dirbuffull
|
||||
notafile:
|
||||
.if .xmatch (drivetype, 1541)
|
||||
lax DIRBLOCKPOS
|
||||
axs #$20; 8 entries per block, $20 bytes per entry
|
||||
stx DIRBLOCKPOS
|
||||
bcs getdirloop; process all entries in a dir block
|
||||
.elseif .xmatch (drivetype, 1571)
|
||||
lax DIRBLOCKPOS
|
||||
axs #.lobyte(-$20); 8 entries per block, $20 bytes per entry
|
||||
stx DIRBLOCKPOS
|
||||
bcc getdirloop; process all entries in a dir block
|
||||
.else; 1581
|
||||
tya
|
||||
and #%11100000; 8 entries per block, $20 bytes per entry
|
||||
;clc
|
||||
adc #$20
|
||||
tay
|
||||
bcc getdirloop; process all entries in a dir block
|
||||
.endif
|
||||
; process next dir block
|
||||
|
||||
.if .xmatch (drivetype, 1541)
|
||||
lax NEXTDIRBLOCKSECTOR
|
||||
tay
|
||||
eor CYCLESTARTENDSECTOR
|
||||
bmi :+; set CYCLESTARTENDSECTOR
|
||||
bne :++
|
||||
; cycle complete
|
||||
tay
|
||||
: sty CYCLESTARTENDSECTOR
|
||||
: txa
|
||||
bpl nextdirsct; jmp
|
||||
.elseif .xmatch (drivetype, 1571)
|
||||
lda NEXTDIRBLOCKSECTOR
|
||||
ldy CYCLESTARTENDSECTOR
|
||||
beq dircycle; set CYCLESTARTENDSECTOR
|
||||
cmp CYCLESTARTENDSECTOR
|
||||
bne nextdirsct
|
||||
|
||||
; cycle complete
|
||||
;sec
|
||||
ror CYCLESTARTENDSECTOR
|
||||
.if (DIRBUFFSIZE < 16)
|
||||
; always fill up a dir buffer that can hold fewer than 2 dir blocks, because if the dir is 2 blocks
|
||||
; big, the dir buffer may otherwise only hold parts of 2 blocks despite having more space
|
||||
bne nextdirsct; jmp
|
||||
.endif
|
||||
.else; 1581
|
||||
jsr getdirtrk
|
||||
ldy NEXTDIRBLOCKSECTOR
|
||||
ldx CYCLESTARTENDTRACK
|
||||
bne :+
|
||||
sta CYCLESTARTENDTRACK
|
||||
sty CYCLESTARTENDSECTOR
|
||||
beq nextdirsct; jmp
|
||||
: cmp CYCLESTARTENDTRACK
|
||||
bne nextdirsct
|
||||
cpy CYCLESTARTENDSECTOR
|
||||
bne nextdirsct
|
||||
|
||||
; cycle complete
|
||||
;sec
|
||||
ror CYCLESTARTENDSECTOR
|
||||
.endif; 1581
|
||||
dirbuffull: lda LOADEDSECTOR
|
||||
sta NEXTDIRBLOCKSECTOR
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
.if DIRBUFFSIZE < 16
|
||||
;ldx NUMFILES; actually number of files - 1
|
||||
.else
|
||||
ldx NUMFILES; actually number of files - 1
|
||||
.endif
|
||||
.else
|
||||
lda CURRDIRBLOCKTRACK
|
||||
sta NEXTDIRBLOCKTRACK
|
||||
|
||||
; the disk was not changed, or the dir has just been read
|
||||
samedisk: ldx NUMFILES; actually number of files - 1
|
||||
.endif; 1581
|
||||
|
||||
findloop:
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
lda NEXTDIRBLOCKSECTOR
|
||||
.else; !1581
|
||||
lda NEXTDIRBLOCKTRACK
|
||||
ldy NEXTDIRBLOCKSECTOR
|
||||
.endif
|
||||
dex ; skip the last file entry to keep it as an overflow entry for load-next and PREPARE_NEXT_FILE
|
||||
.if .xmatch (drivetype, 1541)
|
||||
stx FILEDIRBUFFERINDEX
|
||||
.endif
|
||||
bmi nextdirseg; if the dir buffer does not contain the file, cycle through the directory to find it
|
||||
|
||||
nextfile: lda FILENAMEHASHVALSLO,x
|
||||
eor FILENAMEHASHLO
|
||||
bne findloop
|
||||
ldy FILENAMEHASHVALSHI,x
|
||||
cpy FILENAMEHASHHI
|
||||
bne findloop
|
||||
|
||||
; file found
|
||||
|
||||
.if .xmatch (drivetype, 1541)
|
||||
;sec
|
||||
.elseif (.xmatch (drivetype, 1571))
|
||||
; check for illegal track or sector
|
||||
;sec
|
||||
stx FILEDIRBUFFERINDEX
|
||||
lda .lobyte(DIRTRACKS),x
|
||||
jsr getnumscts
|
||||
stx TEMP
|
||||
ldx FILEDIRBUFFERINDEX
|
||||
ldy .lobyte(DIRTRACKS),x
|
||||
lda .lobyte(DIRSECTORS),x
|
||||
cmp TEMP
|
||||
;bcs filenfound
|
||||
filenotfnd:
|
||||
.else; 1581
|
||||
;lda #$00
|
||||
sta CYCLESTARTENDTRACK
|
||||
sta CYCLESTARTENDSECTOR
|
||||
|
||||
lda DIRTRACKS,x
|
||||
ldy DIRSECTORS,x
|
||||
clc
|
||||
filenotfnd:
|
||||
prpnxtfjmp: jmp prpdnxtfil; is changed to eor prpdnxtfil
|
||||
dec prpnxtfjmp; OPC_EOR_ABS -> OPC_JMP_ABS
|
||||
.endif; 1581
|
||||
.endmacro; FIND_FILE drivetype
|
||||
|
||||
.macro FNAMEHASH drivetype
|
||||
|
||||
fnamehash:
|
||||
.if .xmatch (drivetype, 1541)
|
||||
jsr sertorawd
|
||||
.else
|
||||
lda BLOCKBUFFER + 5,y
|
||||
iny
|
||||
.endif
|
||||
cmp #' ' | $80; $a0 = end of filename
|
||||
beq gethashval
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
sta .lobyte(FILENAME),x
|
||||
.else; 1581
|
||||
sta filename,x
|
||||
.endif; 1581
|
||||
inx
|
||||
cpx #FILENAME_MAXLENGTH
|
||||
bcc fnamehash
|
||||
|
||||
; fall through
|
||||
|
||||
gethashval: txa
|
||||
tay
|
||||
;sec
|
||||
hashloop: sta TEMP
|
||||
tya
|
||||
.if .not .xmatch (drivetype, 1581)
|
||||
adc .lobyte(FILENAME - 1),x
|
||||
.else; 1581
|
||||
adc filename - 1,x
|
||||
.endif; 1581
|
||||
tay
|
||||
adc TEMP
|
||||
dex
|
||||
bne hashloop
|
||||
|
||||
.if .xmatch (drivetype, 1541)
|
||||
specdone: ;sec
|
||||
ror SPECWRAPSECTOR
|
||||
getcustom:
|
||||
.endif
|
||||
rts
|
||||
|
||||
.endmacro; FNAMEHASH drivetype
|
||||
|
||||
.endif; !_DRIVECODE_COMMON_INC_
|
||||
1336
loader/src/drives/drivecode1541.s
Executable file
1336
loader/src/drives/drivecode1541.s
Executable file
File diff suppressed because it is too large
Load diff
1336
loader/src/drives/drivecode1571.s
Executable file
1336
loader/src/drives/drivecode1571.s
Executable file
File diff suppressed because it is too large
Load diff
903
loader/src/drives/drivecode1581.s
Executable file
903
loader/src/drives/drivecode1581.s
Executable file
|
|
@ -0,0 +1,903 @@
|
|||
|
||||
.include "cpu.inc"
|
||||
.include "cia.inc"
|
||||
.include "via.inc"
|
||||
|
||||
.include "drives/drivecode-common.inc"
|
||||
|
||||
ZP_FIRST = $00
|
||||
|
||||
BUFFER = $00
|
||||
SYS_SP = $01
|
||||
JOBCODESTABLE = $02; fixed in ROM
|
||||
JOBTRKSCTTABLE = $0b; fixed in ROM - $0b..$1c
|
||||
FILETRACK = $0b
|
||||
FILESECTOR = $0c
|
||||
FILENAMEHASHLO = $0d
|
||||
FILENAMEHASHHI = $0e
|
||||
NUMFILES = $0f
|
||||
CURRDIRBLOCKTRACK = $10
|
||||
CYCLESTARTENDTRACK = $11
|
||||
CYCLESTARTENDSECTOR = $12
|
||||
NEXTDIRBLOCKTRACK = $13
|
||||
NEXTDIRBLOCKSECTOR = $14
|
||||
FIRSTDIRSECTOR = $15
|
||||
NEXTCONTIGUOUSBLOCK = $16
|
||||
TEMP = $17
|
||||
|
||||
ZP_LAST = $17
|
||||
|
||||
;BLOCKBUFFERJOBTRACK = $1b; fixed in ROM - track for job at buffer 8 ($0b00)
|
||||
;BLOCKBUFFERJOBSECTOR = $1c; fixed in ROM - sector for job at buffer 8 ($0b00)
|
||||
|
||||
DISKCHANGED = $25; fixed in ROM
|
||||
DRIVESTATE = $26; fixed in ROM
|
||||
DRIVEOFF = $00; literal
|
||||
OPEN_FILE_TRACK = $4c; fixed in ROM
|
||||
|
||||
LEDSTATE = $79; fixed in ROM
|
||||
|
||||
IRQVECTOR_LO = $0192
|
||||
IRQVECTOR_HI = $0193
|
||||
HDRS2 = $01bc
|
||||
ROMOS_DIRTRACK81 = $022b
|
||||
OPEN_FILE_SECTOR = $028b
|
||||
|
||||
STROBE_CONTROLLER = $ff54
|
||||
|
||||
OK_DV = $00
|
||||
READ_DV = $80
|
||||
MOTOFFI_DV = $8a
|
||||
SEEK_DV = $8c
|
||||
|
||||
RESET_TIMERB = $cb9f
|
||||
CONTROLLERIRQPERIODFD = $4e20
|
||||
|
||||
BUFFER0 = $0300
|
||||
BUFFERSIZE = $0100
|
||||
|
||||
SENDTABLELO = $0900
|
||||
SENDTABLEHI = $0a00
|
||||
|
||||
BLOCKBUFFER81 = $0b00
|
||||
TRACKOFFSET = 0
|
||||
SECTOROFFSET = 1
|
||||
|
||||
REQUESTEDTRACK = JOBTRKSCTTABLE + (2 * BUFFERINDEX) + TRACKOFFSET
|
||||
REQUESTEDSECTOR = JOBTRKSCTTABLE + (2 * BUFFERINDEX) + SECTOROFFSET
|
||||
LOADEDSECTOR = JOBTRKSCTTABLE + (2 * BUFFERINDEX) + SECTOROFFSET
|
||||
|
||||
LINKTRACK = BLOCKBUFFER81 + TRACKOFFSET
|
||||
LINKSECTOR = BLOCKBUFFER81 + SECTOROFFSET
|
||||
|
||||
BINARY_NIBBLE_MASK = %00001111
|
||||
|
||||
ROMOS_MAXTRACK = $8f; MAXTRACK81 - 1
|
||||
ROMOS_MAXSECTOR = $75; MAXSECTOR81 + 1
|
||||
MAXTRACK81 = 80; literal
|
||||
MAXSECTOR81 = 39; literal
|
||||
|
||||
BUFFERINDEX = (BLOCKBUFFER81 - BUFFER0) / BUFFERSIZE
|
||||
|
||||
.org $0300
|
||||
|
||||
.export cmdfdfix0 : absolute
|
||||
.export cmdfdfix1 : absolute
|
||||
.export cmdfdfix2 : absolute
|
||||
.if (::PLATFORM <> diskio::platform::COMMODORE_128) & (!::DISABLE_WATCHDOG)
|
||||
.export cmdfdfix3 : absolute
|
||||
.export cmdfdfix4 : absolute
|
||||
.endif
|
||||
|
||||
drvcodebeg81: .byte .hibyte(drvcodeend81 - * + $0100 - $01); init transfer count hi-byte
|
||||
|
||||
sysirqvbuf: .word 0
|
||||
|
||||
syszpbuf: .res ZP_LAST - ZP_FIRST + 1
|
||||
|
||||
filename81: .res 16
|
||||
|
||||
.res 24; overflow area for 1541 custom code upload trampoline
|
||||
|
||||
swapzp81: ldx #ZP_LAST - ZP_FIRST
|
||||
: lda ZP_FIRST,x
|
||||
ldy syszpbuf,x
|
||||
sty ZP_FIRST,x
|
||||
sta syszpbuf,x
|
||||
dex
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
FNAMEHASH 1581
|
||||
|
||||
getdirtrk:
|
||||
cmdfdfix1 = * + 1
|
||||
cmdfdfix2 = * + 2
|
||||
lda ROMOS_DIRTRACK81
|
||||
.if DIRTRACK81 = 40
|
||||
rts
|
||||
.endif
|
||||
cmp #40
|
||||
bne :+
|
||||
lda #DIRTRACK81
|
||||
:
|
||||
.if DIRTRACK81 <> 40
|
||||
rts
|
||||
.endif
|
||||
|
||||
trackseek: sta REQUESTEDTRACK
|
||||
sty REQUESTEDSECTOR
|
||||
tax
|
||||
dex
|
||||
stx HDRS2 + (2 * BUFFERINDEX)
|
||||
jsr initcntr81
|
||||
lda #SEEK_DV
|
||||
ldx #BUFFERINDEX
|
||||
jsr STROBE_CONTROLLER
|
||||
|
||||
lda DISKCHANGED
|
||||
ora diskchangd + 1
|
||||
sta diskchangd + 1
|
||||
|
||||
; fall through
|
||||
|
||||
initwdog81: ; the i-flag is set here
|
||||
.if ::DISABLE_WATCHDOG
|
||||
rts
|
||||
.endif
|
||||
lda #.lobyte(uninstall)
|
||||
sta IRQVECTOR_LO
|
||||
lda #.hibyte(uninstall)
|
||||
sta IRQVECTOR_HI
|
||||
lda cmdfdfix2; 0 for FD
|
||||
beq :+
|
||||
lda #$ff
|
||||
sta CIA_TB_LO
|
||||
sta CIA_TB_HI
|
||||
:
|
||||
.if !::DISABLE_WATCHDOG
|
||||
rts
|
||||
.endif
|
||||
|
||||
enablwdg81: lda cmdfdfix2; 0 for FD
|
||||
beq :+
|
||||
ldy #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START
|
||||
sty CIA_CRB
|
||||
bit CIA_ICR
|
||||
rts
|
||||
: lda #IRQ_CLEAR_FLAGS | IRQ_ALL_FLAGS
|
||||
sta VIA_IER; no IRQs from VIA
|
||||
lda #IRQ_SET_FLAGS | IRQ_TIMER_1
|
||||
sta VIA_IER; timer 1 IRQs from VIA
|
||||
ldy #$ff
|
||||
sty VIA_T1C_H
|
||||
rts
|
||||
|
||||
getblock81: sta REQUESTEDTRACK
|
||||
sty REQUESTEDSECTOR
|
||||
getblockag: jsr initcntr81
|
||||
lda #READ_DV
|
||||
ldx #BUFFERINDEX
|
||||
jsr STROBE_CONTROLLER
|
||||
|
||||
lda DISKCHANGED
|
||||
ora diskchangd + 1
|
||||
sta diskchangd + 1
|
||||
|
||||
jsr initwdog81
|
||||
|
||||
lda JOBCODESTABLE + BUFFERINDEX; FD does not return the error status in the accu
|
||||
cmp #OK_DV + 1
|
||||
|
||||
; the link track is returned last so that the z-flag
|
||||
; is set if this block is the file's last one (see FIND_FILE)
|
||||
ldy LINKSECTOR
|
||||
ldx LOADEDSECTOR
|
||||
lda LINKTRACK
|
||||
rts
|
||||
|
||||
initcntr81: lda sysirqvbuf
|
||||
sta IRQVECTOR_LO
|
||||
lda sysirqvbuf + 1
|
||||
sta IRQVECTOR_HI
|
||||
lda cmdfdfix2; 0 for FD
|
||||
beq :+
|
||||
jmp RESET_TIMERB
|
||||
: lda #.lobyte(CONTROLLERIRQPERIODFD)
|
||||
sta VIA_T1C_L
|
||||
lda #.hibyte(CONTROLLERIRQPERIODFD)
|
||||
sta VIA_T1C_H
|
||||
rts
|
||||
|
||||
fadeled: txa
|
||||
tay
|
||||
beq motrledoff
|
||||
: nop
|
||||
bit OPC_BIT_ZP
|
||||
dey
|
||||
bne :-
|
||||
pha
|
||||
jsr busyledoff
|
||||
pla
|
||||
tay
|
||||
: nop
|
||||
bit OPC_BIT_ZP
|
||||
iny
|
||||
bne :-
|
||||
dex
|
||||
bsyledon81: lda #DRIVE_LED
|
||||
ora CIA_PRA
|
||||
ldy #$ff
|
||||
bne store_cia; jmp
|
||||
|
||||
motrledoff: lda DRIVESTATE
|
||||
ora LEDSTATE
|
||||
beq :+
|
||||
|
||||
txa
|
||||
pha
|
||||
|
||||
; fill track cache
|
||||
lda REQUESTEDTRACK
|
||||
ldy REQUESTEDSECTOR
|
||||
jsr getblock81
|
||||
|
||||
; turn off motor
|
||||
jsr initcntr81
|
||||
lda #MOTOFFI_DV
|
||||
ldx #BUFFERINDEX
|
||||
jsr STROBE_CONTROLLER
|
||||
lda #DRIVEOFF; $00
|
||||
sta DRIVESTATE
|
||||
|
||||
pla
|
||||
tax
|
||||
|
||||
busyledoff: lda CIA_PRA
|
||||
and #.lobyte(~DRIVE_LED); turn off drive led
|
||||
ldy #$00
|
||||
store_cia: sta CIA_PRA
|
||||
sty LEDSTATE
|
||||
: rts
|
||||
|
||||
uninstall: jsr getdirtrk
|
||||
jsr trackseek
|
||||
|
||||
ldx LEDSTATE
|
||||
: jsr fadeled
|
||||
lda LEDSTATE
|
||||
bne :-
|
||||
|
||||
ldx SYS_SP
|
||||
txs
|
||||
ldx #ZP_LAST - ZP_FIRST
|
||||
: lda syszpbuf,x
|
||||
sta ZP_FIRST,x
|
||||
dex
|
||||
bpl :-
|
||||
jsr initcntr81
|
||||
|
||||
lda #1
|
||||
sta DISKCHANGED; re-read BAM etc.
|
||||
|
||||
lda #CIA_SET_INTF | FLAG1_IRQ | SERIAL_IRQ | TIMERB_IRQ
|
||||
sta CIA_ICR
|
||||
bit CIA_ICR
|
||||
cli
|
||||
rts
|
||||
|
||||
idleloop: ldx #$00; turn off motor and busy led
|
||||
lda #DRIVE_LED; check if busy led is lit
|
||||
and CIA_PRA
|
||||
beq driveidle
|
||||
dex; fade off the busy led, then turn off motor
|
||||
driveidle: jsr fadeled; fade off the busy led
|
||||
lda CIA_PRB
|
||||
and #ATN_IN | CLK_OUT | CLK_IN | DATA_OUT | DATA_IN
|
||||
eor #ATN_IN | CLK_OUT | CLK_IN | DATA_IN
|
||||
beq driveidle; wait until there is something to do
|
||||
lda CIA_PRB; to be safe, read a second time
|
||||
and #ATN_IN | CLK_OUT | CLK_IN | DATA_OUT | DATA_IN
|
||||
eor #ATN_IN | CLK_OUT | CLK_IN | DATA_IN
|
||||
lsr; check for reset, uninstallation or custom drive code upload
|
||||
beq :+
|
||||
jmp uninstall; check for reset or uninstallation
|
||||
|
||||
: jsr enablwdg81; enable watchdog, the computer might be reset while sending over a
|
||||
; byte, leaving the drive waiting for handshake pulses
|
||||
ENABLE_WATCHDOG
|
||||
|
||||
filename = filename81
|
||||
GET_FILENAME 1581
|
||||
|
||||
; matches against hash of filename in FILENAMEHASHLO/HI
|
||||
BLOCKBUFFER = BLOCKBUFFER81
|
||||
findfile81 = findfile
|
||||
FIND_FILE 1581
|
||||
loadfile81:
|
||||
bcs filenfound
|
||||
|
||||
lda FILENAMEHASHVALSLO + 1,x ; for load-next
|
||||
sta FILENAMEHASHLO ; functionality,
|
||||
lda FILENAMEHASHVALSHI + 1,x ; store hash of
|
||||
sta FILENAMEHASHHI ; next file's name
|
||||
lda DIRTRACKS,x
|
||||
tax
|
||||
|
||||
; check for illegal track or sector
|
||||
beq toillegal
|
||||
cpx ROMOS_MAXTRACK; #MAXTRACK81 - 1
|
||||
beq :+
|
||||
bcs toillegal + 1
|
||||
: cpy ROMOS_MAXSECTOR; #MAXSECTOR81 + 1
|
||||
bcc :+
|
||||
toillegal: sec
|
||||
cmdfdfix0: jmp illegalts; is changed to bit illegalts on FD2000/4000 to disable illegal track or sector error,
|
||||
; ROM variables for logical track/sector boundaries aren't known (probably around MAXTRACKFD = $54)
|
||||
|
||||
: tya
|
||||
pha
|
||||
jsr bsyledon81
|
||||
pla
|
||||
tay; FILESECTOR
|
||||
txa; FILETRACK
|
||||
|
||||
ldx #1
|
||||
stx NEXTCONTIGUOUSBLOCK
|
||||
|
||||
loadblock: sta REQUESTEDTRACK
|
||||
sty REQUESTEDSECTOR
|
||||
: jsr getblockag
|
||||
bcs :-
|
||||
;ldy LINKSECTOR
|
||||
;lda LINKTRACK
|
||||
pha
|
||||
beq :+
|
||||
ldy #$ff
|
||||
: lda #1
|
||||
ldx #0
|
||||
cpx LINKTRACK
|
||||
rol; last block: set lsb, clear lsb otherwise
|
||||
tax
|
||||
lsr
|
||||
lda LINKSECTOR; the file's last block's length (last byte index)
|
||||
pha
|
||||
sty blocksize + 1
|
||||
dey
|
||||
tya
|
||||
eor #$ff
|
||||
bcs :+
|
||||
lda NEXTCONTIGUOUSBLOCK
|
||||
: stx BLOCKBUFFER81 + 1; block index and last block size/next contiguous block index flag
|
||||
; accu: next contiguous block index/block size
|
||||
jsr sendblock; send the block over
|
||||
inc NEXTCONTIGUOUSBLOCK
|
||||
pla; LINKSECTOR
|
||||
tay
|
||||
pla; LINKTRACK
|
||||
bcs fileclosed
|
||||
bne loadblock
|
||||
|
||||
; loading is finished
|
||||
|
||||
clc; all ok after loading
|
||||
|
||||
filenfound: ; branches here with carry set
|
||||
illegalts: ; or illegal t or s
|
||||
|
||||
jsr sendstatus
|
||||
bcs fileclosed
|
||||
|
||||
: lda CIA_PRB
|
||||
and #ATN_IN | CLK_OUT | CLK_IN | DATA_OUT | DATA_IN
|
||||
cmp #ATN_IN | CLK_OUT | CLK_IN | DATA_IN
|
||||
bne :-; wait until host is in idle mode
|
||||
|
||||
lda BLOCKBUFFER81; offset 0: status byte
|
||||
bmi :+; only after successful load
|
||||
|
||||
jmp prpnxtfile; jumps to prpdnxtfil
|
||||
prpdnxtfil: ; always succeeds, trackseek to track in y is valid
|
||||
trseekidle: jsr trackseek
|
||||
: jmp idleloop
|
||||
|
||||
fileclosed: inc BLOCKBUFFER81
|
||||
beq :+; branch if file not found: DATA_OUT remains set, clear it otherwise
|
||||
lda #0
|
||||
sta CIA_PRB
|
||||
: bit CIA_PRB; wait for ATN_IN set,
|
||||
bpl :- ; acknowledgement of the block transfer
|
||||
lda #CLK_OUT; drive busy
|
||||
sta CIA_PRB
|
||||
jmp idleloop
|
||||
|
||||
inittimers: lda cmdfdfix2; 0 for FD
|
||||
beq :+
|
||||
.if ::PLATFORM = diskio::platform::COMMODORE_128
|
||||
lda #5; set burst timer, anything below 5 yields transfer errors
|
||||
sta CIA_TA_LO
|
||||
lda #0
|
||||
sta CIA_TA_HI
|
||||
lda #IOMODE_OUTPUT | COUNT_PHI2 | FORCE_LOAD | CONTINUOUS | TIMER_START; enable burst mode
|
||||
sta CIA_CRA
|
||||
.endif; ::PLATFORM = diskio::platform::COMMODORE_128
|
||||
.if !::DISABLE_WATCHDOG
|
||||
; watchdog initialisation
|
||||
jsr initwdog81
|
||||
lda #CIA_CLR_INTF | EVERY_IRQ
|
||||
sta CIA_ICR
|
||||
lda #CIA_SET_INTF | TIMERB_IRQ
|
||||
sta CIA_ICR
|
||||
bne :++; jmp
|
||||
: jsr initwdog81
|
||||
.endif
|
||||
: rts
|
||||
|
||||
; get custom drive code
|
||||
getcustom: lda #CLK_OUT; 1581
|
||||
sta CIA_PRB
|
||||
lda #CLK_IN
|
||||
: bit CIA_PRB; wait for CLK_IN set
|
||||
beq :-
|
||||
|
||||
ldx SYS_SP
|
||||
txs
|
||||
jsr swapzp81; restore system zeropage values
|
||||
jsr initcntr81
|
||||
lda #CIA_SET_INTF | FLAG1_IRQ | SERIAL_IRQ | TIMERB_IRQ
|
||||
sta CIA_ICR
|
||||
bit CIA_ICR
|
||||
|
||||
customparm = TEMP
|
||||
uploadrout = $2000 - customend + getbyte; as high up in RAM as possible
|
||||
CUSTOMPARAM81 = customparm
|
||||
CUSTOMRECEIVE81 = uploadrout
|
||||
|
||||
sei
|
||||
ldx #customend - getbyte
|
||||
: lda getbyte - 1,x
|
||||
sta uploadrout - 1,x
|
||||
dex
|
||||
bne :-
|
||||
lda #OPC_STA_ZPXI
|
||||
sta uploadrout + getbyterts - getbyte
|
||||
|
||||
;ldx #0
|
||||
stx CIA_PRB; clear DATA_OUT
|
||||
|
||||
ldx #6
|
||||
: jsr getbyte
|
||||
sta customparm - 1,x
|
||||
dex
|
||||
bne :-
|
||||
jmp uploadrout
|
||||
|
||||
; must not clobber x
|
||||
getbyte: DRIVEGETBYTE 1581
|
||||
getbyterts: rts; is changed to sta (zp,x) for custom drive code upload
|
||||
.byte customparm + 2
|
||||
inc customparm + 2
|
||||
bne :+
|
||||
inc customparm + 3
|
||||
: inc customparm + 4
|
||||
bne getbyte
|
||||
inc customparm + 5
|
||||
bmi getbyte
|
||||
jmp (customparm); execute custom drive code
|
||||
customend:
|
||||
|
||||
; carry: clear = ok, set = load error
|
||||
sendstatus: lda #0
|
||||
sta blocksize + 1
|
||||
|
||||
lda #diskio::status::FILE_NOT_FOUND
|
||||
bcs sendblock
|
||||
lda #diskio::status::OK
|
||||
sendblock: sta BLOCKBUFFER81; next contiguous block index/block size
|
||||
|
||||
jsr enablwdg81
|
||||
|
||||
lda #CLK_OUT | DATA_OUT; set DATA_OUT as well so there is a flank only on CLK when signalling ready,
|
||||
sta CIA_PRB; such that just one serial bus read can safely determine block ready (CLK clear) and drive present (DATA set) vs device not present (both clear)
|
||||
lda #DATA_OUT; clear CLK_OUT, set DATA_OUT as signal of presence
|
||||
sta CIA_PRB; block ready signal
|
||||
|
||||
ldx #$20; here, the watchdog timer is polled manually because
|
||||
; an extra-long time-out period is needed since the computer may
|
||||
; still be busy decompressing a large chunk of data,
|
||||
; this is the round counter: $20 * ($ff00 - $0100) = 2,080,768 cycles at 2 MHz is roughly 1 second
|
||||
lda cmdfdfix2; 0 for FD
|
||||
bne waitready
|
||||
|
||||
waitrdyfd: lda VIA_T1C_H; see if the watchdog barked
|
||||
bne :+
|
||||
dex ; if yes, decrease the round counter
|
||||
.if ::DISABLE_WATCHDOG
|
||||
beq :+
|
||||
.else
|
||||
beq timeout; and trigger watchdog on time-out
|
||||
;ldy #$ff
|
||||
sty VIA_T1C_H; reset watchdog time-out
|
||||
.endif
|
||||
: lda #CLK_IN
|
||||
bit CIA_PRB
|
||||
bmi waitrdyfd; wait for ATN_IN clear
|
||||
.if !::DISABLE_WATCHDOG
|
||||
sty VIA_T1C_H; reset watchdog time-out
|
||||
.endif
|
||||
jmp :++
|
||||
|
||||
closefile: sec
|
||||
rts
|
||||
|
||||
waitready: lda CIA_TB_HI; see if the watchdog barked
|
||||
bne :+
|
||||
dex ; if yes, decrease the round counter
|
||||
.if ::DISABLE_WATCHDOG
|
||||
beq :+
|
||||
.else
|
||||
beq timeout; and trigger watchdog on time-out
|
||||
;ldy #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START
|
||||
sty CIA_CRB; reset watchdog time-out
|
||||
.endif
|
||||
: lda #CLK_IN
|
||||
bit CIA_PRB
|
||||
bmi waitready; wait for ATN_IN clear
|
||||
.if !::DISABLE_WATCHDOG
|
||||
sty CIA_CRB; reset watchdog time-out
|
||||
.endif
|
||||
: bne closefile
|
||||
timeout: ENABLE_WATCHDOG
|
||||
|
||||
ldy #$00
|
||||
|
||||
.if ::PLATFORM = diskio::platform::COMMODORE_128
|
||||
|
||||
bit CIA_ICR
|
||||
lda cmdfdfix2; 0 for FD
|
||||
beq fdsendblk
|
||||
ldx #FSM_BUS_DRIVER_OUTPUT | CLK_OUT
|
||||
stx CIA_PRB
|
||||
|
||||
.if ::USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
|
||||
lda BLOCKBUFFER81,y
|
||||
sendloop:
|
||||
blocksize: cpy #$00
|
||||
iny
|
||||
sta CIA_SDR; clock out data byte
|
||||
lda #SERIAL_IRQ
|
||||
ldx #FSM_BUS_DRIVER_OUTPUT; clear CLK_OUT
|
||||
: bit CIA_ICR; wait until data sent
|
||||
beq :-
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START
|
||||
sta CIA_CRB; reset watchdog time-out
|
||||
.else
|
||||
nop; need some slack, as CIA sets the flag a little too early
|
||||
nop
|
||||
.endif
|
||||
stx CIA_PRB; toggle CLK_OUT: signal data sent
|
||||
lda BLOCKBUFFER81,y
|
||||
: bit CIA_PRB; wait for ATN_IN set = data taken
|
||||
bpl :-
|
||||
bcs bcssendone
|
||||
|
||||
cpy blocksize + 1
|
||||
iny
|
||||
sta CIA_SDR; clock out data byte
|
||||
lda #SERIAL_IRQ
|
||||
ldx #FSM_BUS_DRIVER_OUTPUT | CLK_OUT
|
||||
: bit CIA_ICR; wait until data sent
|
||||
beq :-
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START
|
||||
sta CIA_CRB; reset watchdog time-out
|
||||
.else
|
||||
nop; need some slack, as CIA sets the flag a little too early
|
||||
nop
|
||||
.endif
|
||||
stx CIA_PRB; toggle CLK_OUT: signal data sent
|
||||
lda BLOCKBUFFER81,y
|
||||
: bit CIA_PRB; wait for ATN_IN clear = data taken
|
||||
bmi :-
|
||||
bcc sendloop
|
||||
bcssendone: bcs senddone; jmp
|
||||
|
||||
fdsendblk: lda #$38
|
||||
sta VIA_PRA; set to output
|
||||
lda VIA_ACR
|
||||
and #.lobyte(~SHIFT_REG_CONTROL)
|
||||
ora #SHIFT_OUT_T2
|
||||
sta VIA_ACR
|
||||
|
||||
lda BLOCKBUFFER81,y
|
||||
fdsendloop: sta VIA_T2C_H
|
||||
eor #$ff
|
||||
sta VIA_SR; clock out data byte
|
||||
cpy blocksize + 1
|
||||
iny
|
||||
lda #IRQ_SHIFT_REG
|
||||
ldx #FSM_BUS_DRIVER_OUTPUT; clear CLK_OUT
|
||||
: bit CIA_ICR; wait until data sent
|
||||
beq :-
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #$ff
|
||||
sta VIA_T1C_H; reset watchdog time-out
|
||||
.else
|
||||
nop; need some slack
|
||||
nop
|
||||
.endif
|
||||
stx CIA_PRB; toggle CLK_OUT: signal data sent
|
||||
lda BLOCKBUFFER81,y
|
||||
: bit CIA_PRB; wait for ATN_IN set = data taken
|
||||
bpl :-
|
||||
bcs senddone
|
||||
sta VIA_T2C_H
|
||||
eor #$ff
|
||||
sta VIA_SR; clock out data byte
|
||||
cpy blocksize + 1
|
||||
iny
|
||||
lda #IRQ_SHIFT_REG
|
||||
ldx #FSM_BUS_DRIVER_OUTPUT | CLK_OUT
|
||||
: bit CIA_ICR; wait until data sent
|
||||
beq :-
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #$ff
|
||||
sta VIA_T1C_H; reset watchdog time-out
|
||||
.else
|
||||
nop; need some slack, as CIA sets the flag a little too early
|
||||
nop
|
||||
.endif
|
||||
stx CIA_PRB; toggle CLK_OUT: signal data sent
|
||||
lda BLOCKBUFFER81,y
|
||||
: bit CIA_PRB; wait for ATN_IN clear = data taken
|
||||
bmi :-
|
||||
bcc fdsendloop
|
||||
|
||||
.else ; !::USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
|
||||
lda BLOCKBUFFER81,y
|
||||
sendloop: sta CIA_SDR; clock out data byte
|
||||
blocksize: cpy #$00
|
||||
bcs bcswaittkn
|
||||
iny
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START
|
||||
sta CIA_CRB; reset watchdog time-out
|
||||
.endif
|
||||
: bit CIA_PRB; wait for ATN_IN set = data taken
|
||||
bpl :-
|
||||
cpy blocksize + 1
|
||||
lda BLOCKBUFFER81,y
|
||||
sta CIA_SDR; clock out data byte
|
||||
|
||||
bcs waitdtaken
|
||||
iny
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START
|
||||
sta CIA_CRB; reset watchdog time-out
|
||||
.endif
|
||||
: bit CIA_PRB; wait for ATN_IN clear = data taken
|
||||
bmi :-
|
||||
lda BLOCKBUFFER81,y
|
||||
bcc sendloop; jmp
|
||||
|
||||
fdsendblk: lda #$38
|
||||
sta VIA_PRA; set to output
|
||||
lda VIA_ACR
|
||||
and #.lobyte(~SHIFT_REG_CONTROL)
|
||||
ora #SHIFT_OUT_T2
|
||||
sta VIA_ACR
|
||||
|
||||
lda BLOCKBUFFER81,y
|
||||
sta VIA_T2C_H
|
||||
eor #$ff
|
||||
sta VIA_SR; clock out data byte
|
||||
fdsendloop: cpy blocksize + 1
|
||||
bcswaittkn: bcs waittaken
|
||||
iny
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #$ff
|
||||
sta VIA_T1C_H; reset watchdog time-out
|
||||
.endif
|
||||
lda BLOCKBUFFER81,y
|
||||
: bit CIA_PRB; wait for ATN_IN set = data taken
|
||||
bpl :-
|
||||
sta VIA_T2C_H
|
||||
eor #$ff
|
||||
sta VIA_SR; clock out data byte
|
||||
|
||||
cpy blocksize + 1
|
||||
bcs waitdtaken
|
||||
iny
|
||||
.if !::DISABLE_WATCHDOG
|
||||
lda #$ff
|
||||
sta VIA_T1C_H; reset watchdog time-out
|
||||
.endif
|
||||
lda BLOCKBUFFER81,y
|
||||
: bit CIA_PRB; wait for ATN_IN clear = data taken
|
||||
bmi :-
|
||||
sta VIA_T2C_H
|
||||
eor #$ff
|
||||
sta VIA_SR; clock out data byte
|
||||
bcc fdsendloop; jmp
|
||||
|
||||
waitdtaken: bit CIA_PRB; wait for ATN_IN clear = data taken
|
||||
bmi waitdtaken
|
||||
bpl senddone; jmp
|
||||
waittaken: bit CIA_PRB; wait for ATN_IN set = data taken
|
||||
bpl waittaken
|
||||
|
||||
.endif; !::USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
|
||||
senddone: lda cmdfdfix2; 0 for FD
|
||||
bne :+
|
||||
lda #$18
|
||||
sta VIA_PRA
|
||||
:
|
||||
.else; ::PLATFORM <> diskio::platform::COMMODORE_128
|
||||
|
||||
sendloop:
|
||||
.if !::DISABLE_WATCHDOG
|
||||
cmdfdfix3 = * + 1
|
||||
lda #COUNT_PHI2 | FORCE_LOAD | ONE_SHOT | TIMER_START ; is changed to VIA access for FD
|
||||
cmdfdfix4 = * + 1
|
||||
sta CIA_CRB ; 2 + 4 - reset watchdog time-out
|
||||
.endif
|
||||
ldx BLOCKBUFFER81,y ; 4
|
||||
lda SENDTABLELO,x ; 4
|
||||
; = 22 (+6 with watchdog)
|
||||
|
||||
: bit CIA_PRB ; 4
|
||||
bmi :- ; 3
|
||||
sta CIA_PRB ; 4
|
||||
asl ; 2
|
||||
and #.lobyte(~ATNA_ENABLE_OUT) ; 2
|
||||
; = 15
|
||||
|
||||
: bit CIA_PRB ; 4
|
||||
bpl :- ; 3
|
||||
sta CIA_PRB ; 4
|
||||
lda SENDTABLEHI,x ; 4
|
||||
; = 15
|
||||
|
||||
: bit CIA_PRB ; 4
|
||||
bmi :- ; 3
|
||||
sta CIA_PRB ; 4
|
||||
asl ; 2
|
||||
and #.lobyte(~ATNA_ENABLE_OUT) ; 2
|
||||
blocksize: cpy #0 ; 2
|
||||
iny ; 2
|
||||
; = 19
|
||||
|
||||
: bit CIA_PRB ; 4
|
||||
bpl :- ; 3
|
||||
sta CIA_PRB ; 4
|
||||
bcc sendloop ; 3
|
||||
; = 75
|
||||
: bit CIA_PRB; wait for acknowledgement
|
||||
bmi :- ; of the last data byte
|
||||
|
||||
.endif; ::PLATFORM <> diskio::platform::COMMODORE_128
|
||||
|
||||
lda #CLK_OUT; drive busy
|
||||
sta CIA_PRB
|
||||
|
||||
: bit CIA_PRB; wait for ATN_IN set,
|
||||
bpl :- ; acknowledgement of the block transfer
|
||||
|
||||
sei; disable watchdog
|
||||
clc
|
||||
rts
|
||||
|
||||
dcodinit81: lda #CLK_OUT
|
||||
sta CIA_PRB; signal idle to the host, note that ATNA response with ATN_IN low is not possible on 1581,
|
||||
; so a KERNAL LISTEN command cannot be detected for automatic uninstallation
|
||||
jsr swapzp81
|
||||
tsx
|
||||
stx SYS_SP
|
||||
|
||||
lda IRQVECTOR_LO
|
||||
sta sysirqvbuf + 0
|
||||
lda IRQVECTOR_HI
|
||||
sta sysirqvbuf + 1
|
||||
|
||||
ldx #$00
|
||||
: txa
|
||||
sta TEMP
|
||||
lsr
|
||||
lsr
|
||||
alr #%00100010
|
||||
eor TEMP ; bit 3 ^ bit 0
|
||||
and #%00010001; if result is 0: both bits are equal (no swap required)
|
||||
;clc ; if result is 1: swap bits by inverting them
|
||||
adc #%01110111; 0 -> 7, 1 -> 8
|
||||
ora #%01100110; 0 -> 7, 1 -> e
|
||||
eor #%10001000; 0 -> f, 1 -> 6
|
||||
eor TEMP
|
||||
tay
|
||||
and #BINARY_NIBBLE_MASK
|
||||
sta SENDTABLELO,x
|
||||
tya
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tay
|
||||
sta SENDTABLEHI,x
|
||||
inx
|
||||
bne :-
|
||||
|
||||
jsr inittimers
|
||||
|
||||
lda NUMFILES
|
||||
bne :+
|
||||
|
||||
jsr getdirtrk
|
||||
ldy #0
|
||||
jsr trackseek
|
||||
lda #$ff
|
||||
sta NUMFILES
|
||||
: jmp idleloop
|
||||
|
||||
drvcodeend81:
|
||||
DRVCODEND81 = *
|
||||
.export DRVCODEND81
|
||||
|
||||
DIRBUFFSIZE = (SENDTABLELO - *) / 4
|
||||
DIRTRACKS = *
|
||||
DIRSECTORS = DIRTRACKS + DIRBUFFSIZE
|
||||
FILENAMEHASHVALSLO = DIRSECTORS + DIRBUFFSIZE
|
||||
FILENAMEHASHVALSHI = FILENAMEHASHVALSLO + DIRBUFFSIZE
|
||||
|
||||
DIRTRACKS81 = DIRTRACKS
|
||||
|
||||
.assert DIRBUFFSIZE >= 9, error, "***** Dir buffer too small. *****"
|
||||
|
||||
DIRBUFFSIZE81 = DIRBUFFSIZE
|
||||
.export DIRBUFFSIZE81
|
||||
|
||||
.assert * <= BLOCKBUFFER81, error, "***** 1581 drive code too large. *****"
|
||||
|
||||
dinstall: sei
|
||||
lda #CIA_ATN_IN_INPUT | WRITE_PROTECT_OUTPUT | FSM_BUS_DRIVER_DIRECTION_OUTPUT | ATNA_ENABLE_OUT_OUTPUT | CLK_OUT_OUTPUT | CLK_IN_INPUT | DATA_OUT_OUTPUT | DATA_IN_INPUT
|
||||
sta CIA_DDRB
|
||||
lda #CLK_OUT
|
||||
sta CIA_PRB
|
||||
|
||||
ldx #.lobyte(drvcodebeg81 - $01)
|
||||
|
||||
: lda CIA_PRB; wait for ATN_IN set and DATA_IN clear
|
||||
and #ATN_IN | DATA_IN
|
||||
cmp #ATN_IN
|
||||
bne :-
|
||||
|
||||
dgetrout: inx
|
||||
bne :+
|
||||
inc dgetputhi
|
||||
:
|
||||
; must not clobber x
|
||||
lda #%10000000
|
||||
sta BUFFER
|
||||
sta CIA_PRB
|
||||
: lda CIA_PRB
|
||||
: cmp CIA_PRB
|
||||
beq :-
|
||||
lda CIA_PRB
|
||||
and #CLK_IN
|
||||
cmp #CLK_IN
|
||||
ror BUFFER
|
||||
bcc :--
|
||||
lda BUFFER
|
||||
dgetputhi = * + $02
|
||||
sta a:.hibyte(drvcodebeg81 - $01) << 8,x
|
||||
cpx #.lobyte(drvcodeend81 - $01)
|
||||
bne dgetrout
|
||||
dec drvcodebeg81
|
||||
bne dgetrout
|
||||
|
||||
jmp dcodinit81
|
||||
|
||||
drvprgend81:
|
||||
.reloc
|
||||
363
loader/src/hal/hal-c16.inc
Normal file
363
loader/src/hal/hal-c16.inc
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
|
||||
.ifndef _HAL_C16_INC_
|
||||
_HAL_C16_INC_ = 1
|
||||
|
||||
.include "cpu.inc"
|
||||
.include "pio.inc"
|
||||
.include "ted.inc"
|
||||
|
||||
|
||||
.macro CHECK_INSTALL_END_ADDRESS
|
||||
.assert * <= $8000, error, "Install code exceeds $8000, please make sure the DISKIO_INSTALL segment ends below $8000"
|
||||
.endmacro
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
.macro CHECK_RESIDENT_START_ADDRESS
|
||||
RESIDENT_START_ADDRESS = *
|
||||
.endmacro
|
||||
|
||||
.macro CHECK_RESIDENT_END_ADDRESS
|
||||
.assert * <= $8000, error, "Resident code exceeds $8000, please make sure the DISKIO segment ends below $8000"
|
||||
.endmacro
|
||||
.else
|
||||
.macro CHECK_RESIDENT_START_ADDRESS
|
||||
.assert * <= $fd00, error, "Resident code exceeds $fd00, please make sure the DISKIO segment ends below $fd00"
|
||||
.endmacro
|
||||
|
||||
.macro CHECK_RESIDENT_END_ADDRESS
|
||||
.assert * <= $fd00, error, "Resident code exceeds $fd00, please make sure the DISKIO segment ends below $fd00"
|
||||
.endmacro
|
||||
.endif
|
||||
|
||||
|
||||
.macro OK_CLC
|
||||
lda #diskio::status::OK; $00
|
||||
clc; all ok
|
||||
.endmacro
|
||||
|
||||
.macro PREPARE_DRIVE_DISTURBANCE_VALIDATION
|
||||
; disregard drive if it is a 1551, as
|
||||
; it is not connected to the serial bus
|
||||
lda #$01
|
||||
sta USE4DY
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_DRIVE_DOES_NOT_DISTURB_SERIAL_BUS to
|
||||
lda USE4DY; calling LISTEN will set USE4DY to $00 if 1551 at #9,
|
||||
eor #$01 ; $30 if 1551 at #8, and leave it at $01 otherwise,
|
||||
bne to ; then drvlistn will return with $80, $b0, or $01
|
||||
.endmacro
|
||||
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
|
||||
.macro BUFFER_MEMCONFIG
|
||||
GET_MEMCONFIG
|
||||
pha
|
||||
.endmacro
|
||||
|
||||
.macro RESTORE_MEMCONFIG_Y
|
||||
tay
|
||||
pla
|
||||
SET_MEMCONFIG
|
||||
tya
|
||||
.endmacro
|
||||
|
||||
.macro PREPARE_PARALLEL_CHECK
|
||||
lda #$01 ; calling LISTEN will set USE4DY to $00 if 1551 at #9,
|
||||
sta USE4DY; $30 if 1551 at #8, and leave it at $01 otherwise
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_KERNAL_SERIAL_ROUTINES
|
||||
sta TED_ROM_ENABLE
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_KERNAL_SERIAL_ROUTINES_Y
|
||||
sta TED_ROM_ENABLE
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM
|
||||
sta TED_RAM_ENABLE
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM_Y
|
||||
sty TED_RAM_ENABLE
|
||||
.endmacro
|
||||
|
||||
.macro GET_MEMCONFIG
|
||||
lda #ROM_IS_ENABLED
|
||||
and TED_CHARGEN_ADDR
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG
|
||||
.local use_ram
|
||||
|
||||
sta TED_RAM_ENABLE
|
||||
beq use_ram
|
||||
sta TED_ROM_ENABLE
|
||||
use_ram:
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG_Y
|
||||
.local use_ram
|
||||
|
||||
sty TED_RAM_ENABLE
|
||||
beq use_ram
|
||||
sty TED_ROM_ENABLE
|
||||
use_ram:
|
||||
.endmacro
|
||||
.endif; !LOAD_VIA_KERNAL_FALLBACK
|
||||
|
||||
|
||||
IO_PORT_DIR_COMMON = IO_PORT_SERIAL_DATA_IN_INPUT | IO_PORT_SERIAL_CLK_IN_INPUT | IO_PORT_CST_MTR_OUTPUT | IO_PORT_SERIAL_ATN_OUT_OUTPUT | IO_PORT_SERIAL_CLK_OUT_OUTPUT | IO_PORT_SERIAL_DATA_OUT_OUTPUT; $0f
|
||||
|
||||
; effectively, this is the KERNAL flag:
|
||||
; 0 = input = KERNAL,
|
||||
; 1 = output = loader
|
||||
IO_PORT_DIR_KERNAL = IO_PORT_DIR_COMMON | IO_PORT_CST_RD_INPUT ; $0f
|
||||
|
||||
IO_PORT_DIR_OPERATE = IO_PORT_DIR_COMMON | IO_PORT_CST_RD_OUTPUT; $1f
|
||||
|
||||
.macro INSTALL_IDLE
|
||||
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT; $0f
|
||||
sta IO_PORT
|
||||
lda #IO_PORT_DIR_OPERATE
|
||||
sta IO_PORT_DIRECTION
|
||||
.endmacro
|
||||
|
||||
.macro CLEAR store; store is ignored
|
||||
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | (0 & IO_PORT_SERIAL_CLK_OUT) | (0 & IO_PORT_SERIAL_DATA_OUT); $0c
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro CLOSE_FILE
|
||||
SYNC
|
||||
ldx #IO_PORT_CST_MTR | (0 & IO_PORT_SERIAL_ATN_OUT) | IO_PORT_SERIAL_CLK_OUT | (0 & IO_PORT_SERIAL_DATA_OUT); $0a
|
||||
stx IO_PORT
|
||||
: dex
|
||||
bne :-
|
||||
lda IO_PORT
|
||||
asl
|
||||
IDLE
|
||||
.endmacro
|
||||
|
||||
.macro SYNC
|
||||
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | (0 & IO_PORT_SERIAL_DATA_OUT); $0e
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
.local singleclk
|
||||
|
||||
lda TED_CHARGEN_ADDR
|
||||
and #FORCE_SINGLE_CLOCK
|
||||
pha
|
||||
bne singleclk
|
||||
lda #FORCE_SINGLE_CLOCK
|
||||
php
|
||||
sei ; 2
|
||||
ora TED_CHARGEN_ADDR ; 4
|
||||
sta TED_CHARGEN_ADDR ; 4
|
||||
plp ; 4
|
||||
singleclk: ; = 14
|
||||
.endmacro
|
||||
|
||||
.macro POP_CLOCKCONFIG
|
||||
.local singleclk
|
||||
|
||||
pla
|
||||
bne singleclk
|
||||
lda #255 - FORCE_SINGLE_CLOCK
|
||||
php
|
||||
sei ; 2
|
||||
and TED_CHARGEN_ADDR ; 4
|
||||
sta TED_CHARGEN_ADDR ; 4
|
||||
plp ; 4
|
||||
singleclk: ; = 14
|
||||
.endmacro
|
||||
|
||||
.macro SENDBYTE sendstore
|
||||
; does not clobber y
|
||||
|
||||
.local sendbyte
|
||||
.local bitset
|
||||
|
||||
tax
|
||||
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
txa
|
||||
ldx #$07
|
||||
sendbyte: lsr
|
||||
pha
|
||||
lda IO_PORT
|
||||
ora #IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT
|
||||
bcs bitset
|
||||
and #255 - IO_PORT_SERIAL_CLK_OUT
|
||||
bitset: eor #IO_PORT_SERIAL_DATA_OUT
|
||||
sta IO_PORT
|
||||
pla
|
||||
dex
|
||||
bpl sendbyte
|
||||
POP_CLOCKCONFIG
|
||||
.endmacro
|
||||
|
||||
.macro RECEIVEBYTE
|
||||
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
lda #$01
|
||||
: pha
|
||||
pla
|
||||
pha
|
||||
lda #IO_PORT_SERIAL_CLK_OUT
|
||||
eor IO_PORT
|
||||
ldx #IO_PORT_SERIAL_DATA_IN
|
||||
cpx IO_PORT
|
||||
sta IO_PORT
|
||||
pla
|
||||
rol
|
||||
bcc :-
|
||||
tax
|
||||
POP_CLOCKCONFIG
|
||||
txa
|
||||
.endmacro
|
||||
|
||||
.macro SET_FLAGS_N_DATA_V_CLK
|
||||
bit IO_PORT
|
||||
.endmacro
|
||||
|
||||
CLOCK = IO_PORT_CST_MTR | (0 & IO_PORT_SERIAL_CLK_OUT) | (0 & IO_PORT_SERIAL_DATA_OUT)
|
||||
CLOCK_ATN_HI = CLOCK | IO_PORT_SERIAL_ATN_OUT ; 1st and 3rd bit pairs; $0c
|
||||
CLOCK_ATN_LO = CLOCK | (0 & IO_PORT_SERIAL_ATN_OUT); 2nd and 4th bit pairs; $08
|
||||
|
||||
.macro ENABLE_WAITBUSY_KERNAL
|
||||
lda #.lobyte(~IO_PORT_SERIAL_CLK_OUT)
|
||||
and IO_PORT
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro INIT_CLEAR_ATN_OUT_CLEAR_CLK_OUT_CLEAR_DATA_OUT
|
||||
lda #IO_PORT_CST_MTR | (0 & IO_PORT_SERIAL_ATN_OUT) | (0 & IO_PORT_SERIAL_CLK_OUT) | (0 & IO_PORT_SERIAL_DATA_OUT); $08
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro IDLE
|
||||
ldx #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT; $0f
|
||||
stx IO_PORT
|
||||
.endmacro
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
KERNALFILENO = 2
|
||||
|
||||
.macro CLEAR_DATA_OUT_CLEAR_CLK_OUT_ASSERT_ATN
|
||||
lda IO_PORT
|
||||
and #.lobyte(~(IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT))
|
||||
ora #IO_PORT_SERIAL_ATN_OUT
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
.endif
|
||||
|
||||
.macro BRANCH_IF_INSTALLED to
|
||||
lda #IO_PORT_DIR_KERNAL
|
||||
cmp IO_PORT_DIRECTION
|
||||
bne to
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_NOT_INSTALLED to
|
||||
lda #IO_PORT_DIR_KERNAL
|
||||
cmp IO_PORT_DIRECTION
|
||||
beq to
|
||||
.endmacro
|
||||
|
||||
.macro CHECK_AND_BRANCH_IF_DRIVE_PARALLEL to
|
||||
jsr CHECKPARALLEL
|
||||
bcc to
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_DRIVE_PARALLEL to
|
||||
lda USE4DY
|
||||
lsr
|
||||
bcc to
|
||||
.endmacro
|
||||
|
||||
.macro POLL_BLOCK idle_eof, block_not_yet_ready, device_not_present
|
||||
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT; $0f
|
||||
cmp IO_PORT
|
||||
beq idle_eof; branches with carry set on idle/eof
|
||||
|
||||
clc
|
||||
lda #diskio::status::DEVICE_NOT_PRESENT; $fe
|
||||
SET_FLAGS_N_DATA_V_CLK
|
||||
bvc block_not_yet_ready
|
||||
sec
|
||||
bmi device_not_present
|
||||
.endmacro
|
||||
|
||||
.macro SEND_BLOCK_SIGNAL
|
||||
ldy #CLOCK_ATN_LO; use y to ensure that y < $fe when
|
||||
sty IO_PORT ; calling getbyte for the 2 control bytes
|
||||
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
pha; delay
|
||||
pla
|
||||
.endmacro
|
||||
|
||||
.macro RECEIVE_SETUP
|
||||
; nothing to do
|
||||
.endmacro
|
||||
|
||||
.macro RECEIVE store, out
|
||||
.local loop
|
||||
|
||||
; 16 cycles per bitpair ~ 18 cycles at 1 MHz = 18 µs
|
||||
; PAL: 16 / 886723 Hz = 18.04 µs
|
||||
; NTSC: 16 / 894886 Hz = 17.88 µs
|
||||
|
||||
loop: ldx #CLOCK_ATN_HI ; 2
|
||||
lda IO_PORT ; 3
|
||||
stx IO_PORT; ATN high ; 3
|
||||
; = 16
|
||||
|
||||
iny ; 2
|
||||
beq out ; 2
|
||||
lsr ; 2
|
||||
lsr ; 2
|
||||
ldx #CLOCK_ATN_LO ; 2
|
||||
eor IO_PORT ; 3
|
||||
stx IO_PORT; ATN low ; 3
|
||||
; = 16
|
||||
|
||||
lsr ; 2
|
||||
lsr ; 2
|
||||
nop ; 2 - delay
|
||||
nop ; 2 - delay
|
||||
ldx #CLOCK_ATN_HI ; 2
|
||||
eor IO_PORT ; 3
|
||||
stx IO_PORT; ATN high ; 3
|
||||
; = 16
|
||||
|
||||
lsr ; 2
|
||||
lsr ; 2
|
||||
nop ; 2 - delay
|
||||
eor #CLOCK_ATN_HI | (CLOCK_ATN_LO >> 2) ; 2
|
||||
ldx #CLOCK_ATN_LO ; 2
|
||||
eor IO_PORT ; 3
|
||||
stx IO_PORT; ATN low ; 3
|
||||
; = 16
|
||||
|
||||
store ; 5 - sta mem16,y
|
||||
jmp loop ; 3
|
||||
out:
|
||||
.endmacro
|
||||
|
||||
.macro STOREBYTE_ALLRAM
|
||||
storebytio: sta $0000,y
|
||||
.endmacro
|
||||
|
||||
.macro ENDGETBLOCK
|
||||
POP_CLOCKCONFIG
|
||||
.endmacro
|
||||
|
||||
.macro SET_IO_KERNAL
|
||||
INIT_CLEAR_ATN_OUT_CLEAR_CLK_OUT_CLEAR_DATA_OUT
|
||||
lda #IO_PORT_DIR_KERNAL
|
||||
sta IO_PORT_DIRECTION
|
||||
.endmacro
|
||||
|
||||
.endif; !_HAL_C16_INC_
|
||||
607
loader/src/hal/hal-c64-c128.inc
Normal file
607
loader/src/hal/hal-c64-c128.inc
Normal file
|
|
@ -0,0 +1,607 @@
|
|||
|
||||
.ifndef _HAL_C64_C128_INC_
|
||||
_HAL_C64_C128_INC_ = 1
|
||||
|
||||
.include "cia.inc"
|
||||
.include "vic.inc"
|
||||
|
||||
.macro CHECK_INSTALL_END_ADDRESS
|
||||
.assert * <= $d000, error, "Install code exceeds $d000, please make sure the DISKIO_INSTALL segment ends below $d000"
|
||||
.endmacro
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
.macro CHECK_RESIDENT_START_ADDRESS
|
||||
RESIDENT_START_ADDRESS = *
|
||||
.endmacro
|
||||
|
||||
.macro CHECK_RESIDENT_END_ADDRESS
|
||||
.assert (RESIDENT_START_ADDRESS > ENABL) || (* < ENABL), error, "Resident code crosses KERNAL RS232 state variable ENABL"
|
||||
|
||||
.assert * <= $d000, error, "Resident code exceeds $d000, please make sure the DISKIO segment ends below $d000"
|
||||
.endmacro
|
||||
.else
|
||||
.macro CHECK_RESIDENT_START_ADDRESS
|
||||
.assert (* <= $d000) || (* >= $e000), error, "Resident code resides at $d000..$dfff, please make sure the DISKIO segment does not overlap with that memory range"
|
||||
.endmacro
|
||||
|
||||
.macro CHECK_RESIDENT_END_ADDRESS
|
||||
.assert (* <= $d000) || (* >= $e000), error, "Resident code resides at $d000..$dfff, please make sure the DISKIO segment does not overlap with that memory range"
|
||||
.endmacro
|
||||
.endif
|
||||
|
||||
|
||||
.macro OK_CLC
|
||||
; use illegals to save size
|
||||
alr #diskio::status::OK; $00, clc = all ok
|
||||
.endmacro
|
||||
|
||||
.macro PREPARE_DRIVE_DISTURBANCE_VALIDATION
|
||||
; nothing to do
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_DRIVE_DOES_NOT_DISTURB_SERIAL_BUS to
|
||||
; nothing to do
|
||||
.endmacro
|
||||
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
.macro PREPARE_PARALLEL_CHECK
|
||||
; nothing to do
|
||||
.endmacro
|
||||
.endif
|
||||
|
||||
.if PLATFORM <> diskio::platform::COMMODORE_128
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
.macro ENABLE_KERNAL_SERIAL_ROUTINES
|
||||
lda #MEMCONFIG_IO_KERNAL_BASIC
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_KERNAL_SERIAL_ROUTINES_Y
|
||||
ldy #MEMCONFIG_IO_KERNAL_BASIC
|
||||
sty IO_PORT
|
||||
.endmacro
|
||||
.endif; LOAD_VIA_KERNAL_FALLBACK
|
||||
|
||||
.if LOAD_UNDER_D000_DFFF | LOAD_VIA_KERNAL_FALLBACK
|
||||
|
||||
.macro BUFFER_MEMCONFIG
|
||||
lda IO_PORT
|
||||
pha
|
||||
.endmacro
|
||||
|
||||
.macro RESTORE_MEMCONFIG_Y
|
||||
tay
|
||||
pla
|
||||
sta IO_PORT
|
||||
tya
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_IO_SPACE
|
||||
lda #MEMCONFIG_IO
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_IO_SPACE_X
|
||||
ldx #MEMCONFIG_IO
|
||||
stx IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_IO_SPACE_Y
|
||||
ldy #MEMCONFIG_IO
|
||||
sty IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM
|
||||
lda #MEMCONFIG_ALL_RAM
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM_X
|
||||
ldx #MEMCONFIG_ALL_RAM
|
||||
stx IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM_Y
|
||||
ldy #MEMCONFIG_ALL_RAM
|
||||
sty IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro GET_MEMCONFIG
|
||||
lda IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG
|
||||
sta IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG_X
|
||||
stx IO_PORT
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG_Y
|
||||
sty IO_PORT
|
||||
.endmacro
|
||||
.endif; !(LOAD_UNDER_D000_DFFF | LOAD_VIA_KERNAL_FALLBACK)
|
||||
|
||||
.else; PLATFORM = diskio::platform::COMMODORE_128
|
||||
|
||||
.include "mmu.inc"
|
||||
|
||||
.macro DISABLE_BURST_MODE
|
||||
lda #IOMODE_OUTPUT
|
||||
ora CIA1_CRA
|
||||
sta CIA1_CRA
|
||||
.endmacro
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
.macro ENABLE_KERNAL_SERIAL_ROUTINES
|
||||
lda #BANK_0 | SYSTEM_ROM | MID_RAM | LOW_RAM | IO_SPACE
|
||||
sta MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_KERNAL_SERIAL_ROUTINES_Y
|
||||
ldy #BANK_0 | SYSTEM_ROM | MID_RAM | LOW_RAM | IO_SPACE
|
||||
sty MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro START_BURST_LOAD
|
||||
bit CIA1_ICR
|
||||
lda #SERIAL_CLK_OUT
|
||||
eor CIA2_PRA
|
||||
sta CIA2_PRA
|
||||
.endmacro
|
||||
|
||||
.macro GET_BURST_BYTE
|
||||
.local waitburst
|
||||
|
||||
lda #SERIAL_IRQ
|
||||
waitburst: bit CIA1_ICR
|
||||
beq waitburst
|
||||
ldy CIA1_SDR
|
||||
lda #SERIAL_CLK_OUT
|
||||
php
|
||||
sei
|
||||
eor CIA2_PRA
|
||||
sta CIA2_PRA
|
||||
plp
|
||||
tya
|
||||
.endmacro
|
||||
.endif; LOAD_VIA_KERNAL_FALLBACK
|
||||
|
||||
.if LOAD_UNDER_D000_DFFF | LOAD_VIA_KERNAL_FALLBACK
|
||||
|
||||
.macro BUFFER_MEMCONFIG
|
||||
lda MMU_CR
|
||||
pha
|
||||
.endmacro
|
||||
|
||||
.macro RESTORE_MEMCONFIG_Y
|
||||
tay
|
||||
pla
|
||||
sta MMU_CR
|
||||
tya
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_IO_SPACE
|
||||
lda #BANK_0 | HIGH_RAM | MID_RAM | LOW_RAM | IO_SPACE
|
||||
sta MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_IO_SPACE_X
|
||||
ldx #BANK_0 | HIGH_RAM | MID_RAM | LOW_RAM | IO_SPACE
|
||||
stx MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_IO_SPACE_Y
|
||||
ldy #BANK_0 | HIGH_RAM | MID_RAM | LOW_RAM | IO_SPACE
|
||||
sty MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM
|
||||
lda #BANK_0 | HIGH_RAM | MID_RAM | LOW_RAM | RAM_ROM
|
||||
sta MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM_X
|
||||
ldx #BANK_0 | HIGH_RAM | MID_RAM | LOW_RAM | RAM_ROM
|
||||
stx MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro ENABLE_ALL_RAM_Y
|
||||
ldy #BANK_0 | HIGH_RAM | MID_RAM | LOW_RAM | RAM_ROM
|
||||
sty MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro GET_MEMCONFIG
|
||||
lda MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG
|
||||
sta MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG_X
|
||||
stx MMU_CR
|
||||
.endmacro
|
||||
|
||||
.macro SET_MEMCONFIG_Y
|
||||
sty MMU_CR
|
||||
.endmacro
|
||||
.endif; !(LOAD_UNDER_D000_DFFF | LOAD_VIA_KERNAL_FALLBACK)
|
||||
|
||||
.endif; PLATFORM = diskio::platform::COMMODORE_128
|
||||
|
||||
; CIA2 DDRA ($DD02) definitions
|
||||
CIA2_DDRA_COMMON = CIA_SERIAL_DATA_IN_INPUT | CIA_SERIAL_CLK_IN_INPUT | CIA_VIC2_BANK_OUTPUT; $03
|
||||
; effectively, this is the KERNAL flag:
|
||||
; 0 = input = loader,
|
||||
; DATA OUT, CLK OUT, ATN OUT are clear, RS232_TXD is clear ; 1 = output = KERNAL
|
||||
CIA2_DDRA_KERNAL = CIA2_DDRA_COMMON | CIA_SERIAL_ATN_OUT_OUTPUT | CIA_SERIAL_CLK_OUT_OUTPUT | CIA_SERIAL_DATA_OUT_OUTPUT | CIA_RS232_TXD_OUTPUT; $3f
|
||||
|
||||
; DATA OUT, CLK OUT, ATN OUT are set, RS232_TXD input, all bits except VIC bank bits are inputs so that $DD00 writes do not change the bus state
|
||||
CIA2_DDRA_IDLE = CIA2_DDRA_COMMON | CIA_SERIAL_ATN_OUT_INPUT | CIA_SERIAL_CLK_OUT_INPUT | CIA_SERIAL_DATA_OUT_INPUT | CIA_RS232_TXD_INPUT ; $03
|
||||
|
||||
; DATA OUT and CLK OUT are clear, ATN OUT is set, RS232_TXD is output
|
||||
CIA2_DDRA_CLEAR = CIA2_DDRA_COMMON | CIA_SERIAL_ATN_OUT_INPUT | CIA_SERIAL_CLK_OUT_OUTPUT | CIA_SERIAL_DATA_OUT_OUTPUT | CIA_RS232_TXD_OUTPUT; $37
|
||||
|
||||
; DATA OUT, CLK OUT and ATN OUT are clear, RS232_TXD is input
|
||||
CIA2_DDRA_RECEIVE = CIA2_DDRA_COMMON | CIA_SERIAL_ATN_OUT_OUTPUT | CIA_SERIAL_CLK_OUT_OUTPUT | CIA_SERIAL_DATA_OUT_OUTPUT | CIA_RS232_TXD_INPUT ; $3b
|
||||
|
||||
; DATA OUT is clear, CLK OUT and ATN OUT are set, RS232_TXD is input
|
||||
CIA2_DDRA_SYNC = CIA2_DDRA_COMMON | CIA_SERIAL_ATN_OUT_INPUT | CIA_SERIAL_CLK_OUT_INPUT | CIA_SERIAL_DATA_OUT_OUTPUT | CIA_RS232_TXD_INPUT ; $23
|
||||
|
||||
; DATA OUT and ATN OUT are clear, CLK OUT is set, RS232_TXD is input
|
||||
CIA2_DDRA_CLOSE = CIA2_DDRA_COMMON | CIA_SERIAL_ATN_OUT_OUTPUT | CIA_SERIAL_CLK_OUT_INPUT | CIA_SERIAL_DATA_OUT_OUTPUT | CIA_RS232_TXD_INPUT ; $2b
|
||||
|
||||
.macro INSTALL_IDLE
|
||||
lda #CIA2_DDRA_IDLE
|
||||
sta CIA2_DDRA
|
||||
.endmacro
|
||||
|
||||
.macro CLEAR store
|
||||
lda #CIA2_DDRA_CLEAR
|
||||
.ifnblank store
|
||||
store:
|
||||
.endif
|
||||
sta CIA2_DDRA
|
||||
.endmacro
|
||||
|
||||
.macro CLOSE_FILE
|
||||
lda #CIA2_DDRA_SYNC
|
||||
sta CIA2_DDRA
|
||||
ldx #CIA2_DDRA_CLOSE
|
||||
stx CIA2_DDRA
|
||||
: dex
|
||||
bne :-
|
||||
lda CIA2_PRA
|
||||
asl
|
||||
IDLE
|
||||
.endmacro
|
||||
|
||||
.macro SYNC
|
||||
lda #CIA2_DDRA_SYNC
|
||||
sta CIA2_DDRA
|
||||
.endmacro
|
||||
|
||||
.macro SET_FLAGS_N_DATA_V_CLK
|
||||
bit CIA2_PRA
|
||||
.endmacro
|
||||
|
||||
.macro PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
lda VIC2_C128_CLOCK
|
||||
pha
|
||||
lda #0
|
||||
sta VIC2_C128_CLOCK
|
||||
.endmacro
|
||||
|
||||
.macro POP_CLOCKCONFIG
|
||||
pla
|
||||
sta VIC2_C128_CLOCK
|
||||
.endmacro
|
||||
|
||||
.macro SENDBYTE sendstore
|
||||
; does not clobber y
|
||||
|
||||
.local sendbyte
|
||||
.local bitset
|
||||
|
||||
.if USE_2_MHZ
|
||||
tax
|
||||
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
txa
|
||||
.endif
|
||||
ldx #$07
|
||||
sendbyte: lsr
|
||||
pha
|
||||
.if NTSC_COMPATIBILITY
|
||||
nop
|
||||
.endif
|
||||
.ifblank sendstore
|
||||
pha; delay
|
||||
lda CIA2_DDRA
|
||||
and #255 - (SERIAL_ATN_OUT + SERIAL_CLK_OUT)
|
||||
bcs bitset
|
||||
ora #SERIAL_CLK_OUT
|
||||
bitset: eor #SERIAL_DATA_OUT
|
||||
sta CIA2_DDRA
|
||||
pla; delay
|
||||
.else
|
||||
lda GETBYTE_CLOCK_ATN_HI
|
||||
and #255 - (SERIAL_ATN_OUT + SERIAL_CLK_OUT)
|
||||
bcs bitset
|
||||
ora #SERIAL_CLK_OUT
|
||||
bitset: eor #SERIAL_DATA_OUT
|
||||
jsr sendstore
|
||||
.endif
|
||||
pla
|
||||
dex
|
||||
bpl sendbyte
|
||||
.if USE_2_MHZ
|
||||
POP_CLOCKCONFIG
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
.macro RECEIVEBYTE
|
||||
.if USE_2_MHZ
|
||||
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
.endif
|
||||
lda #$01
|
||||
: pha
|
||||
pla
|
||||
pha
|
||||
lda #SERIAL_CLK_OUT
|
||||
eor CIA2_DDRA
|
||||
ldx #SERIAL_DATA_IN
|
||||
cpx CIA2_PRA
|
||||
sta CIA2_DDRA
|
||||
pla
|
||||
rol
|
||||
bcc :-
|
||||
.if USE_2_MHZ
|
||||
tax
|
||||
POP_CLOCKCONFIG
|
||||
txa
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
; RS232 TXD set to output so this bit won't interfere with byte fetch from serial bus
|
||||
CLOCK = CIA2_DDRA_COMMON | CIA_SERIAL_CLK_OUT_OUTPUT | CIA_SERIAL_DATA_OUT_OUTPUT | CIA_RS232_TXD_OUTPUT; $37
|
||||
CLOCK_ATN_HI = CLOCK | CIA_SERIAL_ATN_OUT_INPUT ; 1st and 3rd bit pairs, $37
|
||||
CLOCK_ATN_LO = CLOCK | CIA_SERIAL_ATN_OUT_OUTPUT; 2nd and 4th bit pairs, $3f
|
||||
|
||||
.macro ENABLE_WAITBUSY_KERNAL
|
||||
lda #.lobyte(~(SERIAL_DATA_OUT | SERIAL_CLK_OUT))
|
||||
and CIA2_PRA
|
||||
sta CIA2_PRA
|
||||
.endmacro
|
||||
|
||||
.if LOAD_VIA_KERNAL_FALLBACK
|
||||
KERNALFILENO = 2
|
||||
|
||||
.macro CLEAR_DATA_OUT_CLEAR_CLK_OUT_ASSERT_ATN
|
||||
lda CIA2_PRA
|
||||
and #.lobyte(~(SERIAL_DATA_OUT | SERIAL_CLK_OUT))
|
||||
ora #SERIAL_ATN_OUT
|
||||
sta CIA2_PRA
|
||||
.endmacro
|
||||
.endif
|
||||
|
||||
.macro BRANCH_IF_INSTALLED to
|
||||
lda #CIA2_DDRA_KERNAL
|
||||
cmp CIA2_DDRA
|
||||
bne to
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_NOT_INSTALLED to
|
||||
lda #CIA2_DDRA_KERNAL
|
||||
eor CIA2_DDRA
|
||||
beq to
|
||||
.endmacro
|
||||
|
||||
.macro CHECK_AND_BRANCH_IF_DRIVE_PARALLEL to
|
||||
lda IOPEN + 1
|
||||
cmp #.hibyte($df00); serial: AR fastload vectors point to $DFxx, parallel: IDE64 vectors point to $DExx, IEEE-488 interfaces to $Cxxx
|
||||
bcc to
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_DRIVE_PARALLEL to
|
||||
CHECK_AND_BRANCH_IF_DRIVE_PARALLEL to
|
||||
.endmacro
|
||||
|
||||
.macro IDLE
|
||||
ldx #CIA2_DDRA_IDLE
|
||||
stx CIA2_DDRA
|
||||
.endmacro
|
||||
|
||||
.macro POLL_BLOCK idle_eof, block_not_yet_ready, device_not_present
|
||||
lda #CIA2_DDRA_IDLE
|
||||
cmp CIA2_DDRA
|
||||
beq idle_eof; branches with carry set on idle/eof
|
||||
|
||||
;clc
|
||||
lda #diskio::status::DEVICE_NOT_PRESENT; $fe
|
||||
SET_FLAGS_N_DATA_V_CLK
|
||||
bvc block_not_yet_ready
|
||||
sec
|
||||
bmi device_not_present
|
||||
.endmacro
|
||||
|
||||
.macro SEND_BLOCK_SIGNAL
|
||||
ldy #CIA2_DDRA_RECEIVE; use y to ensure that y < $fe when
|
||||
sty CIA2_DDRA ; calling getbyte for the 2 control bytes
|
||||
|
||||
.if USE_2_MHZ
|
||||
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
|
||||
.else
|
||||
pha; delay
|
||||
pla
|
||||
.endif
|
||||
.if (PLATFORM = diskio::platform::COMMODORE_128) & USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
lda #OPC_BVS
|
||||
sta burstwait
|
||||
.if LOAD_UNDER_D000_DFFF
|
||||
sta burstwaitio
|
||||
.endif
|
||||
.endif; !((PLATFORM = diskio::platform::COMMODORE_128) & USE_ASYNCHRONOUS_BURST_HANDSHAKE)
|
||||
.endmacro
|
||||
|
||||
.macro RECEIVE_SETUP
|
||||
;lda #CLOCK_ATN_HI; = CIA2_DDRA_IDLE
|
||||
sta GETBYTE_CLOCK_ATN_HI
|
||||
.endmacro
|
||||
|
||||
.macro RECEIVE store, out
|
||||
.local getloop
|
||||
.local merge
|
||||
.local entry
|
||||
|
||||
sec; add at label entry below must yield bit 8 set
|
||||
|
||||
.if PLATFORM = diskio::platform::COMMODORE_128
|
||||
.local burstloop
|
||||
.local storeburst
|
||||
.local waitburst
|
||||
.local noburst
|
||||
|
||||
.if .not .xmatch (store, STOREBYTE_ALLRAM)
|
||||
.define burstswit burstwait
|
||||
.else
|
||||
.define burstswit burstwaitio
|
||||
.endif
|
||||
|
||||
bit CIA1_CRA
|
||||
bvs noburst; branch if IO mode is set to output
|
||||
|
||||
.if .not .xmatch (store, STOREBYTE_ALLRAM)
|
||||
lda storebyte + 0
|
||||
sta storeburst + 0
|
||||
lda storebyte + 1
|
||||
sta storeburst + 1
|
||||
lda storebyte + 2
|
||||
sta storeburst + 2
|
||||
.else
|
||||
lda storebytio + 1
|
||||
sta storbytiob + 1
|
||||
lda storebytio + 2
|
||||
sta storbytiob + 2
|
||||
.endif
|
||||
iny
|
||||
|
||||
burstloop: lda CIA2_DDRA ; use the ATN line for the data taken signal in
|
||||
eor #SERIAL_ATN_OUT ; order to keep passive drives from leaving the
|
||||
tax ; silencing loop after too long a period of ATN clear
|
||||
|
||||
.if USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
|
||||
lda #OPC_BVC ^ OPC_BVS; use the CLK line for the incoming data sent signal rather
|
||||
eor burstswit ; than the SERIAL_IRQ flag in CIA1_ICR ($dc0d) in order to
|
||||
sta burstswit ; avoid interference by CIA1 interrupt handlers
|
||||
waitburst: bit CIA2_PRA
|
||||
burstswit: bvs waitburst ; wait for incoming data sent signal
|
||||
|
||||
.else; !USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
|
||||
lda #SERIAL_IRQ
|
||||
waitburst: bit CIA1_ICR
|
||||
beq waitburst
|
||||
|
||||
.endif; !USE_ASYNCHRONOUS_BURST_HANDSHAKE
|
||||
|
||||
lda CIA1_SDR
|
||||
stx CIA2_DDRA ; signal data taken
|
||||
|
||||
.if .not .xmatch (store, STOREBYTE_ALLRAM)
|
||||
storeburst: sta $0000,y
|
||||
.else
|
||||
ENABLE_ALL_RAM_X
|
||||
storbytiob: sta $0000,y
|
||||
ENABLE_IO_SPACE_X
|
||||
.endif
|
||||
iny
|
||||
bne burstloop
|
||||
|
||||
lda #CLOCK_ATN_HI
|
||||
sta CIA2_DDRA
|
||||
bne out; jmp
|
||||
|
||||
noburst = entry
|
||||
.endif; PLATFORM = diskio::platform::COMMODORE_128
|
||||
|
||||
;sec; add below must yield bit 3 set
|
||||
bcs entry; jmp
|
||||
|
||||
; note: between each store to CIA2_DDRA to signal ready for the next bit pair,
|
||||
; 10 cycles must pass before read access of CIA2_PRA:
|
||||
; the drive needs max. 14 cycles to respond with a loop in the form of 'bit VIA1_PRB : bpl/bmi * - 3 : sta VIA1_PRB' -
|
||||
; this means that 18 cycles per bit pair are the minimum
|
||||
|
||||
getloop: lsr ; 2 - -3210HHH
|
||||
lsr ; 2 - --3210HH:H
|
||||
.if NTSC_COMPATIBILITY
|
||||
ldx GETBYTE_CLOCK_ATN_HI ; $37 ; 3
|
||||
.else
|
||||
ldx #CLOCK_ATN_HI ; $37 ; 2
|
||||
.endif
|
||||
ora CIA2_PRA - CLOCK_ATN_HI,x ; 5 - 543210HH - delay
|
||||
stx CIA2_DDRA; sync 3: set ATN high ; 4
|
||||
; = 18
|
||||
|
||||
ror ; 2 - H543210H:H
|
||||
ror ; 2 - HH543210:H
|
||||
ldx #CLOCK_ATN_LO ; $3f ; 2
|
||||
sax merge + $01 ; 4 - --543210
|
||||
.if NTSC_COMPATIBILITY
|
||||
and CIA2_PRA - CLOCK_ATN_LO,x ; 4 - 7654.2..
|
||||
.else
|
||||
and CIA2_PRA ; 4 - 7654.2..
|
||||
.endif
|
||||
stx CIA2_DDRA; sync 4: set ATN low ; 4
|
||||
; = 18
|
||||
|
||||
merge: ora #$00 ; 2 - 76543210
|
||||
store ; 5 - sta mem16,y
|
||||
entry: lax GETBYTE_CLOCK_ATN_HI ; $37 ; 3
|
||||
.if NTSC_COMPATIBILITY
|
||||
adc CIA2_PRA - CLOCK_ATN_HI,x ; 5 - 10HHH... - carry must be set
|
||||
.else
|
||||
adc CIA2_PRA ; 4 - 10HHH... - carry must be set
|
||||
.endif
|
||||
stx CIA2_DDRA; sync 1: set ATN high ; 4
|
||||
; = 18
|
||||
|
||||
iny ; 2
|
||||
beq out ; 2 - clc
|
||||
lsr ; 2 - -10HHH..
|
||||
lsr ; 2 - --10HHH.
|
||||
ldx #CLOCK_ATN_LO ; $3f ; 2
|
||||
.if NTSC_COMPATIBILITY
|
||||
ora CIA2_PRA - CLOCK_ATN_LO,x ; 5 - 3210HHH.
|
||||
.else
|
||||
ora CIA2_PRA ; 4 - 3210HHH.
|
||||
.endif
|
||||
stx CIA2_DDRA; sync 2: set ATN low ; 4
|
||||
; = 18
|
||||
|
||||
jmp getloop ; 3
|
||||
.endmacro
|
||||
|
||||
.macro STOREBYTE_ALLRAM
|
||||
ENABLE_ALL_RAM_X
|
||||
storebytio: sta $0000,y
|
||||
ENABLE_IO_SPACE_X
|
||||
.endmacro
|
||||
|
||||
.macro ENDGETBLOCK
|
||||
.if USE_2_MHZ
|
||||
POP_CLOCKCONFIG
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
.macro SET_IO_KERNAL
|
||||
lda #CIA2_DDRA_KERNAL
|
||||
sta CIA2_DDRA
|
||||
.endmacro
|
||||
|
||||
.endif; !_HAL_C64_C128_INC_
|
||||
33
loader/src/hal/hal.inc
Executable file
33
loader/src/hal/hal.inc
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
.ifndef _HAL_INC_
|
||||
_HAL_INC_ = 1
|
||||
|
||||
.if PLATFORM = diskio::platform::COMMODORE_16
|
||||
.include "hal/hal-c16.inc"
|
||||
.else; PLATFORM <> diskio::platform::COMMODORE_16
|
||||
.include "hal/hal-c64-c128.inc"
|
||||
.endif; PLATFORM <> diskio::platform::COMMODORE_16
|
||||
|
||||
|
||||
.macro DO_UNINSTALL
|
||||
.local waituninst
|
||||
|
||||
SET_IO_KERNAL
|
||||
waituninst: SET_FLAGS_N_DATA_V_CLK
|
||||
bpl waituninst
|
||||
bvc waituninst
|
||||
.endmacro
|
||||
|
||||
; block ready queries are the same for the loader's and KERNAL's protocols
|
||||
|
||||
.macro BRANCH_IF_BLOCK_READY to
|
||||
SET_FLAGS_N_DATA_V_CLK
|
||||
bvs to
|
||||
.endmacro
|
||||
|
||||
.macro BRANCH_IF_BLOCK_NOT_READY to
|
||||
SET_FLAGS_N_DATA_V_CLK
|
||||
bvc to
|
||||
.endmacro
|
||||
|
||||
.endif; !_HAL_INC_
|
||||
1442
loader/src/install.s
Executable file
1442
loader/src/install.s
Executable file
File diff suppressed because it is too large
Load diff
32
loader/src/make-linkfile.pl
Normal file
32
loader/src/make-linkfile.pl
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
my $platform = $ARGV[0];
|
||||
|
||||
my $zp = hex($ARGV[1]);
|
||||
my $install = hex($ARGV[2]);
|
||||
my $resident = hex($ARGV[3]);
|
||||
my $transient = hex($ARGV[4]);
|
||||
|
||||
printf ("MEMORY
|
||||
{
|
||||
ZPRAM: start = \$%x, size = \$%x;
|
||||
ZPRAM2: start = \$%x, size = \$%x;
|
||||
INSTALLRAM: start = \$%x, size = \$%x, file = \"../build/install-$platform.prg\";
|
||||
RESIDENTRAM: start = \$%x, size = \$%x, file = \"../build/loader-$platform.prg\";
|
||||
TRANSIENTRAM: start = \$%x, size = \$%x, file = \"../build/transient-$platform.prg\";
|
||||
}
|
||||
|
||||
SEGMENTS
|
||||
{
|
||||
DISKIO_ZP: load = ZPRAM, type = zp;
|
||||
DISKIO_PLUGIN_ZP: load = ZPRAM2, type = zp, optional = yes;
|
||||
DISKIO: load = RESIDENTRAM;
|
||||
DISKIO_PLUGIN: load = TRANSIENTRAM, optional = yes;
|
||||
DISKIO_INSTALL: load = INSTALLRAM;
|
||||
}
|
||||
",
|
||||
$zp, 0x0100 - $zp,
|
||||
$zp, 0x0100 - $zp,
|
||||
$install - 2, 0x10002 - $install,
|
||||
$resident - 2, 0x10002 - $resident,
|
||||
$transient - 2, 0x10002 - $transient);
|
||||
272
loader/src/make-loadersymbolsinc.pl
Executable file
272
loader/src/make-loadersymbolsinc.pl
Executable file
|
|
@ -0,0 +1,272 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
=head1 NAME
|
||||
|
||||
make-loadersymbolsinc.pl
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script extracts relevant symbols from a ld65-generated map file.
|
||||
The resulting include file can be included in third-party assembly source code.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
make-loadersymbolsinc.pl loader-c64.map > loadersymbols-c64.inc
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use English qw( -no_match_vars ); # OS_ERROR etc.
|
||||
|
||||
|
||||
main();
|
||||
|
||||
sub main
|
||||
{
|
||||
my $version = $ARGV[0];
|
||||
my $project = $ARGV[1];
|
||||
my @input = read_file($ARGV[2]);
|
||||
my ($diskio_segments, $symbols) = extract_all_symbols(@input);
|
||||
print_symbols($version, $project, $diskio_segments, filter_symbols($diskio_segments, $symbols));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub read_file
|
||||
{
|
||||
my ($filename) = @ARG;
|
||||
|
||||
open(my $fh, '<', $filename)
|
||||
or die "cannot read file '$filename': $OS_ERROR";
|
||||
|
||||
my @input = <$fh>;
|
||||
close $fh;
|
||||
|
||||
return @input;
|
||||
}
|
||||
|
||||
sub extract_all_symbols
|
||||
{
|
||||
my @input = @ARG;
|
||||
|
||||
my $current_list;
|
||||
my %diskio_segments;
|
||||
my %symbols;
|
||||
foreach my $i (@input) {
|
||||
|
||||
if ($i =~ qr{list.*?:}) {
|
||||
$current_list = $i;
|
||||
|
||||
} elsif ($current_list =~ qr{Segment}) {
|
||||
# only check against the DISKIO segments
|
||||
if ($i =~ qr{(DISKIO\w*)\s+(\w+)\s+(\w+)}) {
|
||||
my $label = lc $1;
|
||||
$diskio_segments{$label . '_start'} = hex '0x' . $2;
|
||||
$diskio_segments{$label . '_end'} = hex '0x' . $3;
|
||||
}
|
||||
|
||||
} elsif ($current_list =~ qr{Exports}) {
|
||||
# the exported symbols will be filtered by the DISKIO segments
|
||||
if ($i =~ qr{(\w+)\s+(\w+)\s+\w+\s+(\w+)\s+(\w+)}) {
|
||||
# double-entry line
|
||||
$symbols{$1} = hex '0x' . $2;
|
||||
$symbols{$3} = hex '0x' . $4;
|
||||
} elsif ($i =~ qr{(\w+)\s+(\w+)\s+\w+}) {
|
||||
# single-entry line
|
||||
$symbols{$1} = hex '0x' . $2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \%diskio_segments, \%symbols;
|
||||
}
|
||||
|
||||
sub filter_symbols
|
||||
{
|
||||
my ($diskio_segments, $symbols) = @ARG;
|
||||
|
||||
my %filtered_host;
|
||||
my %filtered_drive;
|
||||
my $decompressor;
|
||||
while (my ($name, $address) = each %$symbols) {
|
||||
# do not regard *fix/*fix1 symbols, all-caps or *1 (41/71/81) symbols
|
||||
if ($address && ($name !~ /fix|fix1|[A-Z]|1$/)) {
|
||||
# only symbols in the DISKIO segments are printed
|
||||
if ((($address >= $diskio_segments->{diskio_start})
|
||||
&& ($address <= $diskio_segments->{diskio_end}))
|
||||
|
||||
|| (exists($diskio_segments->{diskio_plugin_start})
|
||||
&& ($address >= $diskio_segments->{diskio_plugin_start})
|
||||
&& ($address <= $diskio_segments->{diskio_plugin_end}))
|
||||
|
||||
|| (($address >= $diskio_segments->{diskio_install_start})
|
||||
&& ($address <= $diskio_segments->{diskio_install_end}))
|
||||
|
||||
|| (($address >= $diskio_segments->{diskio_zp_start})
|
||||
&& ($address <= $diskio_segments->{diskio_zp_end}))
|
||||
|
||||
|| (exists($diskio_segments->{diskio_plugin_zp_start})
|
||||
&& ($address >= $diskio_segments->{diskio_plugin_zp_start})
|
||||
&& ($address <= $diskio_segments->{diskio_plugin_zp_end})))
|
||||
{
|
||||
$filtered_host{$name} = $address;
|
||||
}
|
||||
} elsif (($name =~ /config_/) || ($name =~ /status_/)) {
|
||||
$filtered_host{$name} = $address;
|
||||
} elsif (($name =~ /1$/) && ($name !~ /fix1$/)) {
|
||||
$filtered_drive{$name} = $address;
|
||||
} elsif ($name =~ /DECOMPRESSOR_(\S+)/) {
|
||||
$decompressor = $1;
|
||||
}
|
||||
}
|
||||
|
||||
return \%filtered_host, \%filtered_drive, $decompressor;
|
||||
}
|
||||
|
||||
sub print_symbols
|
||||
{
|
||||
my ($version, $project, $diskio_segments, $host_symbols, $drive_symbols, $decompressor) = @ARG;
|
||||
|
||||
my @host_symbols_sorted_by_address =
|
||||
sort { $host_symbols->{$a} <=> $host_symbols->{$b} } keys %{$host_symbols};
|
||||
|
||||
my @drive_symbols_sorted_by_address =
|
||||
sort { $drive_symbols->{$a} <=> $drive_symbols->{$b} } keys %{$drive_symbols};
|
||||
|
||||
my $target = ($diskio_segments->{diskio_plugin_start}) ? "customdrivecode" : "prg";
|
||||
for (@host_symbols_sorted_by_address) {
|
||||
if("save" eq $_ ) {
|
||||
$target = "save";
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
chomp(my $datetime = `date -R`);
|
||||
print "; repository version " . $version . ", built on " . $datetime . " for project \"" . $project . "\" using\n";
|
||||
print "; make PLATFORM=" . $ENV{'_PLATFORM_'} . " " . $target . " INSTALL=" . $ENV{'INSTALL'} . " RESIDENT=" . $ENV{'RESIDENT'};
|
||||
unless ($target =~ /prg/) {
|
||||
print " TRANSIENT=" . $ENV{'TRANSIENT'}
|
||||
}
|
||||
print " ZP=" . $ENV{'ZP'} . " PROJECT=" . $ENV{'PROJECT'} . "\n\n";
|
||||
|
||||
print "; configuration\n";
|
||||
foreach my $name (sort (keys(%{$host_symbols}))) {
|
||||
if ($name =~ /config_/) {
|
||||
if ($name =~ /config_DECOMPRESSOR/) {
|
||||
print_symbol($name, $host_symbols->{$name}, $decompressor);
|
||||
} else {
|
||||
print_symbol($name, $host_symbols->{$name});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "\n; status codes\n";
|
||||
foreach my $name (@host_symbols_sorted_by_address) {
|
||||
if ($name =~ /status_/) {
|
||||
print_hex_symbol($name, $host_symbols->{$name});
|
||||
}
|
||||
}
|
||||
|
||||
my $zp_end = $diskio_segments->{diskio_zp_end};
|
||||
if (exists($diskio_segments->{diskio_plugin_zp_end})) {
|
||||
$zp_end = $diskio_segments->{diskio_plugin_zp_end} > $diskio_segments->{diskio_zp_end} ? $diskio_segments->{diskio_plugin_zp_end} : $diskio_segments->{diskio_zp_end};
|
||||
}
|
||||
|
||||
print "\n; zeropage ";
|
||||
printf '$%.2x-$%.2x', $diskio_segments->{diskio_zp_start}, $zp_end + 1;
|
||||
print "\n";
|
||||
print_hex_symbol("loader_zp_first", $host_symbols->{"loader_zp_first"});
|
||||
print_segment_symbols($host_symbols, $diskio_segments->{diskio_zp_start}, $zp_end, @host_symbols_sorted_by_address);
|
||||
|
||||
print "\n; install ";
|
||||
printf '$%.4x-$%.4x', $diskio_segments->{diskio_install_start} + 2, $diskio_segments->{diskio_install_end} + 1;
|
||||
print "\n";
|
||||
# only one relevant symbol ("install"), stop after that so that other symbols from overlaying segments (transient) will be printed there instead
|
||||
print_segment_symbols($host_symbols, $diskio_segments->{diskio_install_start} + 2, $diskio_segments->{diskio_install_start} + 2, @host_symbols_sorted_by_address);
|
||||
|
||||
print "\n; resident ";
|
||||
printf '$%.4x-$%.4x', $diskio_segments->{diskio_start} + 2, $diskio_segments->{diskio_end} + 1;
|
||||
print "\n";
|
||||
print_segment_symbols($host_symbols, $diskio_segments->{diskio_start} + 2, $diskio_segments->{diskio_end}, @host_symbols_sorted_by_address);
|
||||
|
||||
unless ($target =~ /prg/) {
|
||||
if ($diskio_segments->{diskio_plugin_start}) {
|
||||
print "\n; transient ";
|
||||
printf '$%.4x-$%.4x', $diskio_segments->{diskio_plugin_start} + 2, $diskio_segments->{diskio_plugin_end} + 1;
|
||||
print "\n";
|
||||
print_segment_symbols($host_symbols, $diskio_segments->{diskio_plugin_start} + 2, $diskio_segments->{diskio_plugin_end}, @host_symbols_sorted_by_address);
|
||||
}
|
||||
|
||||
unless ($target =~ /save/) {
|
||||
print "\n; drive\n";
|
||||
print_drive_symbols($drive_symbols, "41", @drive_symbols_sorted_by_address);
|
||||
print "\n";
|
||||
print_drive_symbols($drive_symbols, "71", @drive_symbols_sorted_by_address);
|
||||
print "\n";
|
||||
print_drive_symbols($drive_symbols, "81", @drive_symbols_sorted_by_address);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub print_segment_symbols
|
||||
{
|
||||
my ($symbols, $start, $end, @symbols_sorted_by_address) = @ARG;
|
||||
|
||||
foreach my $name (@symbols_sorted_by_address) {
|
||||
if ($name =~ /config_|status_|loader_zp_first/) {
|
||||
next;
|
||||
}
|
||||
|
||||
my $address = $symbols->{$name};
|
||||
if ($address == 0) {
|
||||
next;
|
||||
}
|
||||
|
||||
if (($address >= $start)
|
||||
&& ($address <= $end)) {
|
||||
print_hex_symbol($name, $symbols->{$name});
|
||||
|
||||
$symbols->{$name} = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub print_drive_symbols
|
||||
{
|
||||
my ($symbols, $filter, @symbols_sorted_by_address) = @ARG;
|
||||
|
||||
foreach my $name (@symbols_sorted_by_address) {
|
||||
if ($name =~ /$filter$/) {
|
||||
print_hex_symbol($name, $symbols->{$name});
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub print_symbol
|
||||
{
|
||||
my ($name, $address) = @ARG;
|
||||
|
||||
my $format = "%-31s = %d%s\n";
|
||||
printf $format, $name, $address, $ARG[2] ? "; " . $ARG[2] : "";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub print_hex_symbol
|
||||
{
|
||||
my ($name, $address) = @ARG;
|
||||
|
||||
my $address_length = ($address < 256) ? '2' : '4';
|
||||
my $format = '%-31s = $%.' . $address_length . "x\n";
|
||||
printf $format, $name, $address;
|
||||
|
||||
return;
|
||||
}
|
||||
1408
loader/src/resident.s
Executable file
1408
loader/src/resident.s
Executable file
File diff suppressed because it is too large
Load diff
1145
loader/src/save.s
Normal file
1145
loader/src/save.s
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue