;-------------------------------------------------------------------------------
; COVERT BITOPS loader/depacker V2.1
; with REU+SuperRAM, and 1541/1571/1581/CMD FD/CMD HD support
;
; EXOMIZER compressor by Magnus Lind
; PUCRUNCH compressor by Pasi Ojala
; SuperRAM routines & REU code optimization by Ninja/The Dreams
; 1581/CMD FD/CMD HD information from Ninja & DocBacardi /The Dreams
; Rest by Lasse ™”rni
;
; Thanks to K.M/TABOO for inspiration on badline detection and 1-bit transfer,
; Marko M„kel„ for his original irqloader.s (huge inspiration), MuOn for
; testing the 2-bit transfer on a NTSC C64 and Pixman for suggesting REU
; support.
;-------------------------------------------------------------------------------

                processor 6502

;-------------------------------------------------------------------------------
; Include your loader configuration file at this point!
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; Defines derived from the compile options (need not be changed)
;-------------------------------------------------------------------------------

CONFIGSIZE      = REU_SUPPORT+SLOWLOAD_SUPPORT ;Configuration size in bytes

                if ADDITIONAL_ZEROPAGE>0
loadtempreg     = zpbase2+0      ;Temp variables for the loader
bufferstatus    = zpbase2+1      ;Bytes in REU/fastload buffer
fileopen        = zpbase2+2      ;File open indicator
fastloadstatus  = zpbase2+3      ;Fastloader active indicator
                if REU_SUPPORT>0
newreu1         = zpbase2+4
newreu2         = zpbase2+5
                endif
                endif

destlo          = zpbase+0
desthi          = zpbase+1

;-------------------------------------------------------------------------------
; Other defines
;-------------------------------------------------------------------------------

MW_DATA_LENGTH  = 32            ;Bytes in one M-W command

IRQ_SPEED       = $28           ;$1c07 value for 1541, suggested safe value
                                ;from Graham

status          = $90           ;Kernal zeropage variables
messages        = $9d
fa              = $ba

acsbf           = $01           ;Diskdrive variables: Buffer 1 command
trkbf           = $08           ;Buffer 1 track
sctbf           = $09           ;Buffer 1 sector
iddrv0          = $12           ;Disk drive ID
drvtemp         = $06           ;Temp variable
id              = $16           ;Disk ID
buf             = $0400         ;Sector data buffer
initialize      = $d005         ;Initialize routine in 1541 ROM

reustatus       = $df00         ;REU registers
command         = $df01
c64base         = $df02
reubase         = $df04
translen        = $df07
irqmask         = $df09
control         = $df0a

ciout           = $ffa8         ;Kernal routines
listen          = $ffb1
second          = $ff93
unlsn           = $ffae
acptr           = $ffa5
chkin           = $ffc6
chkout          = $ffc9
chrin           = $ffcf
chrout          = $ffd2
close           = $ffc3
open            = $ffc0
setmsg          = $ff90
setnam          = $ffbd
setlfs          = $ffba
clrchn          = $ffcc
getin           = $ffe4
load            = $ffd5
save            = $ffd8

;-------------------------------------------------------------------------------
; Resident portion of loader (routines that you're going to use at runtime)
;-------------------------------------------------------------------------------

                if LOADFILE_UNPACKED>0
;-------------------------------------------------------------------------------
; LOADFILE
;
; Loads an unpacked file
;
; Parameters: X (low),Y (high): Address of null-terminated filename
; Returns: C=0 OK, C=1 error (A holds errorcode)
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

loadfile:       jsr openfile
                jsr getbyte             ;Get startaddress lowbyte
                bcs loadfile_fail       ;If EOF at first byte, error
  lda #<image_packed
                sta destlo
                jsr getbyte             ;Get startaddress highbyte
  lda #>image_packed
                sta desthi
                ldy #$00
loadfile_loop:  jsr getbyte
                bcs loadfile_eof
                if LOAD_UNDER_IO>0
                jsr disableio           ;Allow loading under I/O area
                endif
                sta (destlo),y
                if LOAD_UNDER_IO>0
                jsr enableio
                endif
                iny
                bne loadfile_loop
                inc desthi
                jmp loadfile_loop
loadfile_eof:   cmp #$01                ;Returncode 0 = OK, others error
loadfile_fail:  rts
                endif

                if LOADFILE_EXOMIZER>0
;-------------------------------------------------------------------------------
; LOADFILE_EXOMIZER
;
; Loads a file packed with EXOMIZER
;
; Parameters: X (low),Y (high): Address of null-terminated filename
; Returns: C=0 OK, C=1 error (A holds errorcode)
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

tabl_bi         = depackbuffer
tabl_lo         = depackbuffer+52
tabl_hi         = depackbuffer+104

zp_len_lo       = zpbase+0
zp_src_lo       = zpbase+1
zp_src_hi       = zpbase+2
zp_bits_lo      = zpbase+3
zp_bits_hi      = zpbase+4
zp_bitbuf       = zpbase+5
zp_dest_lo      = zpbase+6
zp_dest_hi      = zpbase+7

loadfile_exomizer:
                jsr openfile
                tsx
                stx exomizer_stackptr+1
                jsr exomizer_depack
                clc
                rts

; -------------------------------------------------------------------
; EXOMIZER depackroutine by Magnus Lind
; Modified by Lasse ™”rni for interrupt disabling (loading under I/O)
; and to call getbyte directly without need for a "wrapper" routine
; that slows down decrunching/loading
; -------------------------------------------------------------------
;
; Copyright (c) 2002 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.
;
; exodecruncher.s, a part of the exomizer v1.0 release
; -------------------------------------------------------------------
; 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 adress.
; -------------------------------------------------------------------

; -------------------------------------------------------------------
; jsr this label to decrunch, it will in turn init the tables and
; call the decruncher
; no constraints on register content, however the
; decimal flag has to be #0 (it almost always is, otherwise do a cld)
exomizer_depack:
; -------------------------------------------------------------------
; init zeropage (12 bytes)
;
  ldy #0
  ldx #3
init_zp:
        php
  jsr getbyte
        bcs exomizer_fail
        plp
  sta zp_bitbuf - 1,x
  dex
  bne init_zp
; -------------------------------------------------------------------
; calculate tables (53 bytes)
; x and y must be #0 when entering
;
nextone:
  inx
  tya
  and #$0f
  beq shortcut    ; starta på ny sekvens

  lda zp_bits_lo
  adc tabl_lo-1,y
  tax

  lda zp_bits_hi
  adc tabl_hi-1,y
shortcut:
  sta tabl_hi,y
  txa
  sta tabl_lo,y

  ldx #4
  jsr get_bits    ; clears x-reg.
  sta tabl_bi,y

  stx zp_bits_lo    ; zp_bits_hi is already 0 because
  tax     ; we called get_bits with x = 4
  inx
  sec
rolle:
  rol zp_bits_lo
  rol zp_bits_hi
  dex
  bne rolle   ; c = 0 after this
skip:
  iny
  cpy #52
  bne nextone
  ldy #0
  beq begin
; -------------------------------------------------------------------
; get x + 1 bits (1 byte)
;
get_bit1:
  inx
; -------------------------------------------------------------------
; get bits (31 bytes)
;
; args:
;   x = number of bits to get
; returns:
;   a = #bits_lo
;   x = #0
;   c = 0
;   zp_bits_lo = #bits_lo
;   zp_bits_hi = #bits_hi
; notes:
;   y is untouched
;   other status bits are set to (a == #0)
; -------------------------------------------------------------------
get_bits:
  lda #$00
  sta zp_bits_lo
  sta zp_bits_hi
  cpx #$01
  bcc bits_done
  lda zp_bitbuf
bits_next:
  lsr
  bne bits_ok
        php
  jsr getbyte
        bcs exomizer_fail
        plp
  ror
bits_ok:
  rol zp_bits_lo
  rol zp_bits_hi
  dex
  bne bits_next
  sta zp_bitbuf
  lda zp_bits_lo
bits_done:
  rts
; -------------------------------------------------------------------
; Failure when reading a byte: restore stackptr and exit
;
exomizer_fail:                          ;A premature EOF is treated as an
exomizer_stackptr:                      ;error; return directly to caller
        ldx #$00
        txs
        rts
; -------------------------------------------------------------------
; main copy loop (16 bytes)
;
copy_next_hi:
  dex
  dec zp_dest_hi
  dec zp_src_hi
copy_next:
  dey
        if LOAD_UNDER_IO>0
        jsr disableio
        endif
  lda (zp_src_lo),y
literal_entry:
  sta (zp_dest_lo),y
        if LOAD_UNDER_IO>0
        jsr enableio
        endif
copy_start:
  tya
  bne copy_next
  txa
  bne copy_next_hi
; -------------------------------------------------------------------
; decruncher entry point, needs calculated tables (5 bytes)
; x and y must be #0 when entering
;
begin:
  jsr get_bit1
  beq sequence
; -------------------------------------------------------------------
; literal handling (13 bytes)
;
literal_start:
  lda zp_dest_lo
  bne avoid_hi
  dec zp_dest_hi
avoid_hi:
  dec zp_dest_lo
        php
        jsr getbyte
        bcs exomizer_fail
        plp
        if LOAD_UNDER_IO>0
        bcs sequence
        jsr disableio
        endif
  bcc literal_entry
; -------------------------------------------------------------------
; count zero bits + 1 to get length table index (10 bytes)
; y = x = 0 when entering
;
sequence:
next1:
  iny
  jsr get_bit1
  beq next1
  cpy #$11
  bcs bits_done
; -------------------------------------------------------------------
; calulate length of sequence (zp_len) (17 bytes)
;
  ldx tabl_bi - 1,y
  jsr get_bits
  adc tabl_lo - 1,y
  sta zp_len_lo
  lda zp_bits_hi
  adc tabl_hi - 1,y
  pha
; -------------------------------------------------------------------
; here we decide what offset table to use (20 bytes)
; x is 0 here
;
  bne nots123
  ldy zp_len_lo
  cpy #$04
  bcc size123
nots123:
  ldy #$03
size123:
  ldx tabl_bit - 1,y
  jsr get_bits
  adc tabl_off - 1,y
  tay
; -------------------------------------------------------------------
; prepare zp_dest (11 bytes)
;
  sec
  lda zp_dest_lo
  sbc zp_len_lo
  sta zp_dest_lo
  bcs noborrow
  dec zp_dest_hi
noborrow:
; -------------------------------------------------------------------
; calulate absolute offset (zp_src) (27 bytes)
;
  ldx tabl_bi,y
  jsr get_bits;
  adc tabl_lo,y
  bcc skipcarry
  inc zp_bits_hi
  clc
skipcarry:
  adc zp_dest_lo
  sta zp_src_lo
  lda zp_bits_hi
  adc tabl_hi,y
  adc zp_dest_hi
  sta zp_src_hi
; -------------------------------------------------------------------
; prepare for copy loop (6 bytes)
;
  ldy zp_len_lo
  pla
  tax
  bcc copy_start
; -------------------------------------------------------------------
; two small static tables (6 bytes)
;
tabl_bit:
  dc.b 2,4,4
tabl_off:
  dc.b 48,32,16
; -------------------------------------------------------------------
; end of decruncher
; -------------------------------------------------------------------
                endif

                if LOADFILE_PUCRUNCH>0

;-------------------------------------------------------------------------------
; LOADFILE_PUCRUNCH
;
; Loads a file packed with PUCRUNCH
;
; Parameters: X (low),Y (high): Address of null-terminated filename
; Returns: C=0 OK, C=1 error (A holds errorcode)
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

lzpos           = zpbase
bitstr          = zpbase+2

table           = depackbuffer

loadfile_pucrunch:
                jsr openfile
                tsx
                stx pucrunch_stackptr+1
;  lda #4
;  sta $d020
                jsr getbyte                     ;Throw away file startaddress
                jsr getbyte

;-------------------------------------------------------------------------------
; PUCRUNCH DECOMPRESSOR by Pasi Ojala
;
; SHORT+IRQLOAD         354 bytes
; no rle =~             -83 bytes -> 271
; fixed params =~       -48 bytes -> 306
;                       223 bytes
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

        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
        sta outpos+1
        jsr getbyt
        sta outpos+2
        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
        clc
        sbc #0
        sta mg21+1      ; (2<<maxGamma) - 1
        jsr getbyt
        sta elzpb+1

        ldx #$03
2$      jsr getbyt      ; Get 3 bytes, 2 unused (exec address)
        dex             ; and rleUsed. X is 0 after this loop
        bne 2$

        ;jsr getbyt     ; exec address
        ;sta lo+1       ; lo
        ;jsr getbyt
        ;sta hi+1       ; hi
        ;
        ;jsr getbyt     ; rleUsed
        ;ldx #0

        tay
        sty bitstr
0$      beq 1$          ; Y == 0 ?
        jsr getbyt
        sta table,x
        inx
        dey
        bne 0$
1$      ; setup bit store - $80 means empty
        lda #$80
        sta bitstr
        jmp 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)

        cpx #32         ; 31-32 -> C clear, 32-32 -> C set..
        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)
        ldx #3
        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:    clc             ; Loading ended OK
        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 getbyt2     ; clears Carry, X = 0
        ; Note: Already eor:ed in the compressor..
        ;eor #255       ; offset LSB 2's complement -1 (i.e. -X = ~X+1)
        adc outpos+1    ; -offset -1 + curpos (C is clear)
        ldx lzpos       ; xstore = LZLEN (read before it's overwritten)
        sta lzpos

        lda outpos+2
        sbc lzpos+1     ; takes C into account
        sta lzpos+1     ; copy X+1 number of chars from LZPOS to outpos+1
        ;ldy #0         ; Y was 0 originally, we don't change it

        inx             ; adjust for cpx#$ff;bne -> bne

lzslow  if LOAD_UNDER_IO>0
        jsr disableio
        endif
        lda (lzpos),y   ; using abs,y is 3 bytes longer, only 1 cycle/byte faster
        jsr outpos
        iny             ; Y does not wrap because X=0..255 and Y initially 0
        dex
        bne lzslow      ; X loops, (256,1..255)
        jmp main

putch   if LOAD_UNDER_IO>0
        jsr disableio
        endif
outpos  sta $aaaa       ; ** parameter
        inc outpos+1    ; ZP
        bne putchok
        inc outpos+2    ; ZP
putchok if LOAD_UNDER_IO>0
        jmp enableio
        else
        rts
        endif

getnew  pha             ; 1 Byte/3 cycles
        jsr getbyte
        bcs pucrunch_fail
0$      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
n; ** 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 **
getbyt2 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

pucrunch_fail:                          ;A premature EOF is treated as an
pucrunch_stackptr:                      ;error; return directly to caller
                ldx #$00
                txs
                rts
                endif

;-------------------------------------------------------------------------------
; OPENFILE
;
; Opens a file either with slow or fast loader, or from REU if it has been
; buffered. If a file is already open, does nothing!
;
; Parameters: X (low),Y (high): Address of null-terminated filename
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

openfile:       lda fileopen            ;A file already open?
                beq open_ok
                rts
open_ok:        if LONG_NAMES>0
                stx destlo
                sty desthi
                else
                stx filename
                sty filename+1
                endif
                if REU_SUPPORT>0
                lda reufiles            ;Any files in REU?
                beq open_skipreu
                sta loadtempreg
                lda #$00                ;Start from the first REU directory
                sta newreu1
                sta newreu2
open_reudirpageloop:
                ldy #%10110001
                jsr getreubuffer
                if LONG_NAMES>0         ;X=0 when returning
                stx open_reunext+1
                endif
open_reudirloop:
                if LONG_NAMES>0
                ldy #$00
open_reucomparename:
                lda loadbuffer,x
                cmp (destlo),y
                bne open_reunext
                inx
                iny
                bne open_reucomparename
open_reunext:   ldx #$00
                cmp #$a0                ;Name endmark?
                beq open_reunameok
                else
open_reudirloop:lda loadbuffer,x
                cmp filename
                bne open_reunext
                lda loadbuffer+1,x
                cmp filename+1
                beq open_reunameok
open_reunext:
                endif
                dec loadtempreg         ;Checked all REU files?
                beq open_skipreu
                txa
                clc
                adc #$10                ;All files on directory page checked?
                tax
                bcc open_reudirloop
                bcs open_reudirpageloop
open_reunameok: lda loadbuffer+14,x
                sta newreu1
                lda loadbuffer+15,x
                sta newreu2
                ldy #%10110001          ;Negative fileopen indicator -
                sty fileopen            ;opened from REU
reu_fillbuffer: jsr getreubuffer        ;X=0 when returning from here, which
                jmp fillbuffer_common   ;is needed in fillbuffer_common to
                                        ;reset the buffer counter
open_skipreu:
                endif
                inc fileopen            ;File opened
;  lda #4
;  sta $d020
                if SLOWLOAD_SUPPORT>0
                lda usefastload
                bne fastopen

;-------------------------------------------------------------------------------
; SLOWOPEN
;
; Opens a file without fastloader.
;
; Parameters: A:0 (it always is at this point)
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

slowopen:       if LONG_NAMES>0
                tay
                endif
                jsr kernalon
                if LONG_NAMES>0
slowopen_nameloop:
                iny
                lda (destlo),y
                bne slowopen_nameloop
                tya
                ldx destlo
                ldy desthi
                else
                lda #$03
                ldx #<filename
                ldy #>filename
                endif
                jsr setnam
                lda #$02
                ldy #$00
                jsr setlfsdevice
                jsr open
                ldx #$02                ;File number
                jmp chkin
                endif

;-------------------------------------------------------------------------------
; FASTOPEN
;
; Opens a file with fastloader. Uses an asynchronous protocol inspired by
; Marko M„kel„'s work when sending the filename.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

fastopen:
;  pha
;  lda #$0a
;  sta $d020
;  pla
       jsr initfastload        ;If fastloader is not yet initted,
                                        ;init it now
;  pha
;  lda #$0c
;  sta $d020
;  pla
                if LONG_NAMES>0
                ldy #$00
fastload_sendouter:
                lda (destlo),y
                sta loadtempreg
                pha
                ldx #$08                ;Bit counter
                else
                ldx #$01
fastload_sendouter:
                if REU_SUPPORT>0        ;If REU support, filename has to be
                lda filename,x          ;preserved
                sta loadtempreg
                endif
                ldy #$08                ;Bit counter
                endif
fastload_sendinner:
                bit $dd00               ;Wait for both DATA & CLK to go high
                bpl fastload_sendinner
                bvc fastload_sendinner
                if LONG_NAMES=0
                if REU_SUPPORT=0        ;If no REU support, rotate the filename
                lsr filename,x          ;bits directly
                else
                lsr loadtempreg         ;Otherwise, have to rotate the temp
                endif                   ;register
                else
                lsr loadtempreg
                endif
                lda #$10
;PEX:
 sei
                ora $dd00
                bcc fastload_zerobit
                eor #$30
fastload_zerobit:
                sta $dd00
;PEX:
 cli
                lda #$c0                ;Wait for CLK & DATA low (answer from
fastload_sendack:                       ;the diskdrive)
                bit $dd00
                bne fastload_sendack
                lda #$ff-$30            ;Set DATA and CLK high
;PEX:
 sei
                and $dd00
                sta $dd00
;PEX:
 cli
                if LONG_NAMES>0
                dex
                bne fastload_sendinner
                iny
                pla
                bne fastload_sendouter
                else
                dey
                bne fastload_sendinner
                dex
                bpl fastload_sendouter
                endif
                sta $d07a               ;SCPU to slow mode
fastload_predelay:
                dex                     ;Delay to make sure the 1541 has
                bne fastload_predelay   ;set DATA high before we continue

fastload_fillbuffer:
                if REU_SUPPORT>0
                ldy fileopen
                bmi reu_fillbuffer
                endif
                sta $d07a                 ;SCPU to slow mode
fastload_fbwait:bit $dd00                 ;Wait for 1541 to signal data ready by
                bvc fastload_fbwait       ;setting CLK high
                pha                       ;Some delay before beginning
                pla
                pha
                pla
                ldx #$00
fastload_fillbufferloop:                  ;1bit receive code
                nop
                nop
                nop
                ldy #$08                  ;Bit counter
fastload_bitloop:
                nop
                lda #$10
;PEX:
 sei
                eor $dd00                 ;Take databit
                sta $dd00                 ;Store reversed clockbit
;PEX:
 cli
                asl
                ror loadbuffer,x
                dey
                bne fastload_bitloop
                if BORDER_FLASHING>0
                dec $d020
                inc $d020
                endif
                inx
                bne fastload_fillbufferloop

fillbuffer_common:
                stx bufferstatus                ;X is 0 here
                ldx #$fe
                lda loadbuffer                  ;Full 254 bytes?
                bne fastload_fullbuffer
                ldx loadbuffer+1                ;End of load?
                bne fastload_noloadend
                stx fileopen                    ;Clear fileopen indicator
                lda loadbuffer+2                ;Read the return/error code
                sta fileclosed+1
fastload_noloadend:
                dex
fastload_fullbuffer:
                stx fastload_endcomp+1
fileclosed:     lda #$00
                sec
                rts

;-------------------------------------------------------------------------------
; GETBYTE
;
; Gets a byte from an opened file.
;
; Parameters: -
; Returns: C=0 OK, A contains byte
;          C=1 File stream ended. A contains the error code:
;              $00 - OK, end of file
;              $01 - Sector read error (only with fastloading)
;              $02 - File not found
; Modifies: A
;-------------------------------------------------------------------------------

getbyte:        lda fileopen
                beq fileclosed
                stx getbyte_restx+1
                sty getbyte_resty+1
                if REU_SUPPORT>0
                bmi fastload_getbyte            ;REU mode
                endif
getbyte_fileopen:
                if SLOWLOAD_SUPPORT>0
                lda usefastload
                beq slowload_getbyte
                endif
fastload_getbyte:
                ldx bufferstatus
                lda loadbuffer+2,x
                inx
fastload_endcomp:cpx #$00                       ;Reach end of buffer?
                stx bufferstatus
                bcc getbyte_restx
                pha
                jsr fastload_fillbuffer
                pla
getbyte_done:   clc
getbyte_restx:  ldx #$00
getbyte_resty:  ldy #$00
                rts

                if SLOWLOAD_SUPPORT>0
slowload_getbyte:
                jsr chrin
                ldx status
                beq getbyte_done
                pha
                txa
                and #$03
                sta fileclosed+1        ;EOF - store return code
                dec fileopen
                jsr close_kernaloff
                pla
                ldx fileclosed+1        ;Check return code, if nonzero,
                cpx #$01                ;return with carry set and return
                bcc getbyte_restx       ;code in A
                txa
                bcs getbyte_restx
                endif

                if HISCORE_SUPPORT>0
;-------------------------------------------------------------------------------
; SAVEHISCORES
;
; Uninitializes fastloader and saves the hiscore/configuration file.
; Fastloader will be re-initted next time when it is needed.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

savehiscores:   jsr kernalon
                lda #HINAMELENGTH+3
                ldx #<scratch
                ldy #>scratch
                jsr setnam
                lda #$0f                        ;Delete the old file
                ldy #$0f
                jsr setlfsdevice
                jsr open
                lda #$0f
                jsr close
                jsr setlfsdevice
                jsr sethiscorename
                lda #<hiscores
                sta destlo
                lda #>hiscores
                sta desthi
                ldx #<(hiscores+HISCORESIZE+CONFIGSIZE)
                ldy #>(hiscores+HISCORESIZE+CONFIGSIZE)
                lda #destlo
                jsr save
                jmp kernaloff

;-------------------------------------------------------------------------------
; SETHISCORENAME
;
; Subroutine for setting the hiscore name with SETNAM for loading/saving.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

sethiscorename: lda #$00
                sta messages                    ;Disable Kernal messages
                sta fastloadstatus              ;Mark fastloader as uninitted
                lda #HINAMELENGTH
                ldx #<hiscorename
                ldy #>hiscorename
                jmp setnam
                endif

                if LOAD_UNDER_IO>0
;-------------------------------------------------------------------------------
; DISABLEIO
;
; Stores $01 status, disables interrupts & IO area.
;
; Parameters: -
; Returns: -
; Modifies: -
;-------------------------------------------------------------------------------

disableio:      pha
                lda $01
                sta enableio_01+1
                sei
                lda #$34
                sta $01
                pla
                rts

;-------------------------------------------------------------------------------
; ENABLEIO
;
; Restores $01 status and enables interrupts
;
; Parameters: -
; Returns: -
; Modifies: -
;-------------------------------------------------------------------------------

enableio:       pha
enableio_01:    lda #$36
                sta $01
                cli
                pla
                rts
                endif

;-------------------------------------------------------------------------------
; SETLFSDEVICE
;
; Gets the last used device number and performs a SETLFS.
;
; Parameters: -
; Returns: -
; Modifies: X
;-------------------------------------------------------------------------------

setlfsdevice:   ldx fa
                jmp setlfs

;-------------------------------------------------------------------------------
; KERNALON
;
; Switches KERNAL on to prepare for slow loading. Saves state of $01.
;
; Parameters: -
; Returns: -
; Modifies: A,X
;-------------------------------------------------------------------------------

kernalon:       lda $01
                sta kernaloff+1
                lda #$36
                sta $01
                rts

                if SLOWLOAD_SUPPORT>0
;-------------------------------------------------------------------------------
; CLOSE_KERNALOFF
;
; Closes file 2 and then restores state of $01.
;
; Parameters: -
; Returns: -
; Modifies: A
;-------------------------------------------------------------------------------

close_kernaloff:lda #$02
                jsr close
                jsr clrchn
                endif

;-------------------------------------------------------------------------------
; KERNALOFF
;
; Restores state of $01.
;
; Parameters: -
; Returns: -
; Modifies: A
;-------------------------------------------------------------------------------

kernaloff:      lda #$36
                sta $01
il_ok:          rts

;-------------------------------------------------------------------------------
; INITFASTLOADER
;
; Uploads the fastloader to disk drive memory and starts it.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

initfastload:   lda fastloadstatus      ;If fastloader already initted,
                bne il_ok               ;do nothing
                sta ifl_mwstring+2      ;Drivecode starts at lowbyte 0
                tay
                if SLOWLOAD_SUPPORT>0
                lda usefastload
                beq il_ok
                endif
                jsr kernalon
                inc fastloadstatus
                lda #>drivecode_drv
                sta ifl_mwstring+1
                lda #>drivecode_c64
                sta ifl_senddata+2
                lda #(drivecodeend_drv-drivecode_drv+MW_DATA_LENGTH-1)/MW_DATA_LENGTH
                sta loadtempreg         ;Number of "packets" to send
                bne ifl_nextpacket
ifl_sendmw:     lda ifl_mwstring,x      ;Send M-W command (backwards)
                jsr ciout
                dex
                bpl ifl_sendmw
                ldx #MW_DATA_LENGTH
ifl_senddata:   lda drivecode_c64,y     ;Send one byte of drivecode
                jsr ciout
                iny
                bne ifl_notover
                inc ifl_senddata+2
ifl_notover:    inc ifl_mwstring+2      ;Also, move the M-W pointer forward
                bne ifl_notover2
                inc ifl_mwstring+1
ifl_notover2:   dex
                bne ifl_senddata
                jsr unlsn               ;Unlisten to perform the command
ifl_nextpacket: lda fa                  ;Set drive to listen
                jsr listen
                lda #$6f
                jsr second
                ldx #$05
                dec loadtempreg         ;All "packets" sent?
                bpl ifl_sendmw
                dex
ifl_sendme:     lda ifl_mestring,x      ;Send M-E command (backwards)
                jsr ciout
                dex
                bpl ifl_sendme
                jsr unlsn
                jmp kernaloff

;-------------------------------------------------------------------------------
; DRIVECODE - Code executed in the disk drive.
;-------------------------------------------------------------------------------

drivecode_c64:                  ;Address in C64's memory
                rorg $0500      ;Address in diskdrive's memory

drivecode_drv:  jsr drv_detect  ;Detect drive type
drv_loop:       cli             ;File loop: Get filename first
                if LONG_NAMES>0
                ldx #$00
                else
                ldx #$01
                endif
drv_nameloop:   ldy #$08  ;Bit counter
drv_namebitloop:
drv_1800ac1:    lda $1800
                bmi drv_quit    ;Quit if ATN is low
                and #$05        ;Wait for CLK or DATA going low
                beq drv_namebitloop
                lsr   ;Read the data bit
                lda #$02  ;Pull the other line low to acknowledge
                bcc drv_namezero ;the bit being received
                lda #$08
drv_namezero:   ror drv_filename,x ;Store the data bit
drv_1800ac2:    sta $1800
drv_namewait:
drv_1800ac3:    lda $1800 ;Wait for either line going high
                and #$05
                cmp #$05
                beq drv_namewait
                lda #$00
drv_1800ac4:    sta $1800 ;Set both lines high
                dey
                bne drv_namebitloop ;Loop until all bits have been received
                sei             ;Disable interrupts after first byte
                if LONG_NAMES>0
                inx
                lda drv_filename-1,x ;End of filename?
                bne drv_nameloop
                else
                dex
                bpl drv_nameloop
                endif
                lda #$08            ;CLK low, data isn't available
drv_1800ac5:    sta $1800
drv_dirtrk:     ldx $1000
drv_dirsct:     ldy $1000           ;Read disk directory
drv_dirloop:    jsr drv_readsector  ;Read sector
                bcs drv_loadend     ;If failed, return error code
                ldy #$02
drv_nextfile:   lda buf,y       ;File type must be PRG
                and #$83
                cmp #$82
                bne drv_notfound
                if LONG_NAMES>0
                ldx #$03
                sty drv_namecmploop+1
                lda #$a0                ;Make an endmark at the 16th letter
                sta buf+19,y
drv_namecmploop:lda buf,x
                cmp drv_filename-3,x    ;Check against each letter of filename
                bne drv_namedone        ;until at the endzero
                inx
                bne drv_namecmploop
drv_namedone:   cmp #$a0                ;If got to a $a0, name correct
                beq drv_found
                else
                lda buf+3,y
                cmp drv_filename
                bne drv_notfound
                lda buf+4,y
                cmp drv_filename+1
                beq drv_found
                endif
drv_notfound:   tya
                clc
                adc #$20
                tay
                bcc drv_nextfile
                ldy buf+1       ;Go to next directory block, go on until no
                ldx buf         ;more directory blocks
                bne drv_dirloop
drv_filenotfound:
                ldx #$02        ;Return code $02 = File not found
drv_loadend:    stx buf+2
                lda #$00
                sta buf
                sta buf+1
                beq drv_sendblk

drv_quit:                       ;If ATN, exit to drive ROM code
drv_drivetype:  ldx #$00
                bne drv_not1541
                lda #$3a                  ;Restore default speed
                sta $1c07
                jmp initialize

drv_not1541:    rts

drv_found:      iny
drv_nextsect:   ldx buf,y       ;File found, get starting track & sector
                beq drv_loadend ;At file's end? (return code $00 = OK)
                lda buf+1,y
                tay
                jsr drv_readsector ;Read the data sector
                bcs drv_loadend
drv_sendblk:    lda #$04                  ;Bitpair counter/
                ldx #$00                  ;compare-value for CLK-line
drv_1800ac6:    stx $1800                 ;CLK & DATA high -> ready to go
drv_sendloop:   ldx buf
drv_zpac1:      stx drvtemp
                tay                       ;Bitpair counter
drv_sendloop_bitpair:
                ldx #$00
drv_zpac2:      lsr drvtemp
                bcs drv_sendloop_wait1
                ldx #$02
drv_sendloop_wait1:
drv_1800ac7:    bit $1800                 ;Wait until CLK high
                bne drv_sendloop_wait1
drv_1800ac8:    stx $1800
                ldx #$00
drv_zpac3:      lsr drvtemp
                bcs drv_sendloop_wait2
                ldx #$02
drv_sendloop_wait2:
drv_1800ac9:    bit $1800
                beq drv_sendloop_wait2    ;Wait until CLK low
drv_1800ac10:   stx $1800
                dey
                bne drv_sendloop_bitpair
                inc drv_sendloop+1
                bne drv_sendloop
drv_sendloop_endwait:
drv_1800ac11:   bit $1800                 ;Wait for CLK high
                bne drv_sendloop_endwait
                asl                       ;Set CLK low, DATA high
drv_1800ac12:   sta $1800                 ;(more data yet not ready)

drv_senddone:   lda buf                   ;First 2 bytes zero marks end of loading
                ora buf+1                 ;(3rd byte is the return code)
                bne drv_nextsect
drv_1800ac13:   lda $1800                 ;Set CLK high, preserve DATA
                and #$02
drv_1800ac14:   sta $1800
                lda #$04
drv_endwaitclk:
drv_1800ac15:   bit $1800       ;Wait for CLK to go high
                bne drv_endwaitclk
                lda #$00        ;Set DATA high
drv_1800ac16:   sta $1800
                jmp drv_loop

drv_readsector:
drv_readtrk:    stx $1000
drv_readsct:    sty $1000
                ldy #RETRIES              ;Retry counter
drv_retry:      lda #$80
                ldx #1
drv_execjsr:    jsr drv_1541exec          ;Exec buffer 1 job
                cmp #$02                  ;Error?
                bcc drv_success
drv_skipid:     dey                       ;Decrease retry counter
                bne drv_retry
drv_failure:    ldx #$01                  ;Return code $01 - Read error
drv_success:    sei                       ;Make sure interrupts now disabled
                rts

drv_1541exec:   tax
                lda $1c00               ;Led on
                ora #$08
                sta $1c00
                cli                     ;Allow interrupts & execute command
                stx $01
drv_1541execwait:
                lda $01
                bmi drv_1541execwait
                pha
                lda id                  ;Handle disk ID change
                sta iddrv0
                lda id+1
                sta iddrv0+1
                lda $1c00               ;Led off
                and #$f7
                sta $1c00
                pla
                rts

drv_fdexec:     jsr $ff54               ;FD2000 fix by Ninja
                lda $03
                rts

drv_1541dirtrk: dc.b 18
drv_1541dirsct: dc.b 1
drv_1581dirsct: dc.b 3
drv_filename:

        ;Drive detection for 41/71/81/HD/FD support

drv_detect:     lda $fea0                 ;Recognize drive family
                ldx #3                    ;(from Dreamload)
drv_floop:      cmp drv_family-1,x
                beq drv_ffound
                dex                       ;If unrecognized, assume 1541
                bne drv_floop
                beq drv_idfound
drv_ffound:     lda drv_idloclo-1,x
                sta drv_idlda+1
                lda drv_idlochi-1,x
                sta drv_idlda+2
drv_idlda:      lda $fea4                 ;Recognize drive type
                ldx #3                    ;3 = CMD HD
drv_idloop:     cmp drv_id-1,x            ;2 = CMD FD
                beq drv_idfound           ;1 = 1581
                dex                       ;0 = 1541
                bne drv_idloop
drv_idfound:    stx drv_drivetype+1       ;Store drive type
                lda drv_1800lo,x
                sta drv_patch1800lo+1
                lda drv_1800hi,x
                sta drv_patch1800hi+1
                ldy #16
drv_patchloop:  ldx drv_1800ofslo,y
                lda drv_1800ofshi,y
                sta drv_patch1800sta1+2
                sta drv_patch1800sta2+2
drv_patch1800lo:lda #$00                  ;Patch all $1800 accesses
drv_patch1800sta1:
                sta drivecode_drv+1,x
drv_patch1800hi:lda #$00
drv_patch1800sta2:
                sta drivecode_drv+2,x
                dey
                bpl drv_patchloop
                ldx drv_drivetype+1       ;On 1541, speedup controller IRQs
                bne drv_skip1c07
                lda #IRQ_SPEED
                sta $1c07
drv_skip1c07:   lda drv_dirtrklo,x        ;Patch directory
                sta drv_dirtrk+1
                lda drv_dirtrkhi,x
                sta drv_dirtrk+2
                lda drv_dirsctlo,x
                sta drv_dirsct+1
                lda drv_dirscthi,x
                sta drv_dirsct+2
                lda drv_execlo,x          ;Patch job exec address
                sta drv_execjsr+1
                lda drv_exechi,x
                sta drv_execjsr+2
                lda drv_jobtrklo,x        ;Patch job track/sector
                sta drv_readtrk+1
                clc
                adc #$01
                sta drv_readsct+1
                lda drv_jobtrkhi,x
                sta drv_readtrk+2
                adc #$00
                sta drv_readsct+2
                lda drv_zp,x              ;Patch zeropage temp usage
                sta drv_zpac1+1
                sta drv_zpac2+1
                sta drv_zpac3+1
                rts

drv_family:     dc.b $43,$0d,$ff
drv_idloclo:    dc.b $a4,$c6,$e9
drv_idlochi:    dc.b $fe,$e5,$a6
drv_id:         dc.b "8","F","H"

drv_1800ofslo:  dc.b <drv_1800ac1
                dc.b <drv_1800ac2
                dc.b <drv_1800ac3
                dc.b <drv_1800ac4
                dc.b <drv_1800ac5
                dc.b <drv_1800ac6
                dc.b <drv_1800ac7
                dc.b <drv_1800ac8
                dc.b <drv_1800ac9
                dc.b <drv_1800ac10
                dc.b <drv_1800ac11
                dc.b <drv_1800ac12
                dc.b <drv_1800ac13
                dc.b <drv_1800ac14
                dc.b <drv_1800ac15
                dc.b <drv_1800ac16

drv_1800ofshi:  dc.b >drv_1800ac1
                dc.b >drv_1800ac2
                dc.b >drv_1800ac3
                dc.b >drv_1800ac4
                dc.b >drv_1800ac5
                dc.b >drv_1800ac6
                dc.b >drv_1800ac7
                dc.b >drv_1800ac8
                dc.b >drv_1800ac9
                dc.b >drv_1800ac10
                dc.b >drv_1800ac11
                dc.b >drv_1800ac12
                dc.b >drv_1800ac13
                dc.b >drv_1800ac14
                dc.b >drv_1800ac15
                dc.b >drv_1800ac16

drv_1800lo:     dc.b <$1800,<$4001,<$4001,<$8000
drv_1800hi:     dc.b >$1800,>$4001,>$4001,>$8000

drv_dirtrklo:   dc.b <drv_1541dirtrk,<$022b,<$54,<$2ba7
drv_dirtrkhi:   dc.b >drv_1541dirtrk,>$022b,>$54,>$2ba7
drv_dirsctlo:   dc.b <drv_1541dirsct,<drv_1581dirsct,<$56,<$2ba9
drv_dirscthi:   dc.b >drv_1541dirsct,>drv_1581dirsct,>$56,>$2ba9

drv_execlo:     dc.b <drv_1541exec,<$ff54,<drv_fdexec,<$ff4e
drv_exechi:     dc.b >drv_1541exec,>$ff54,>drv_fdexec,>$ff4e

drv_jobtrklo:   dc.b <$0008,<$000d,<$000d,<$2802
drv_jobtrkhi:   dc.b >$0008,>$000d,>$000d,>$2802

drv_zp:         dc.b $06,$0b,$0b,$06

drivecodeend_drv:
                rend
drivecodeend_c64:

                if REU_SUPPORT>0
;-------------------------------------------------------------------------------
; GETREUBUFFER
;
; Reads or writes 256 bytes from the REU or from the SuperRAM.
;
; Parameters: newreu1,newreu2:REU address bits 8-23
;             Y:Command (%10110001 = read, %10110000 = write)
; Returns: X:0
;          newreu1,newreu2 incremented for next page
; Modifies: A,X
;-------------------------------------------------------------------------------

getreubuffer:   ldx newreu1
                lda newreu2                 ; get REU-pointers
                inc newreu1                 ; increment them for the next
                bne grskip                  ; block
                inc newreu2
grskip:         bit usereu                  ; REU or SRAM?
                bmi getsrambuffer
                stx reubase+1               ; set REU-registers
                sta reubase+2
                sty command
                ldx #$00
                rts

getsrambuffer:  clc
                adc $d27d                   ; add first available SRAM-bank
                cpy #%10110001              ; load or save?
                bne sramsave
sramload:       stx srammod2+2
                sta srammod2+3
                ldx #$00
sramloop2:
srammod2:       dc.b $bf,$00,$00,$02         ; lda $020000,x
                sta loadbuffer,x
                inx
                bne sramloop2
                rts

sramsave:       stx srammod1+2
                sta srammod1+3
                ldx #$00
sramloop:       lda loadbuffer,x
srammod1:       dc.b $9f,$00,$00,$02         ; sta $020000,x
                inx
                bne sramloop
                rts
                endif

;-------------------------------------------------------------------------------
; M-W and M-E command strings
;-------------------------------------------------------------------------------

ifl_mwstring:   dc.b MW_DATA_LENGTH,$00,$00,"W-M"

ifl_mestring:   dc.b >drivecode_drv, <drivecode_drv, "E-M"

;-------------------------------------------------------------------------------
; Loader variables, if not on zeropage
;-------------------------------------------------------------------------------

                if ADDITIONAL_ZEROPAGE=0
loadtempreg:    dc.b 0          ;Temp variable for the loader
bufferstatus:   dc.b 0          ;Bytes in REU/fastload buffer
fileopen:       dc.b 0          ;File open indicator
fastloadstatus: dc.b 0          ;Fastloader active indicator
                if REU_SUPPORT>0
newreu1:        dc.b 0
newreu2:        dc.b 0
                endif
                endif

                if REU_SUPPORT>0
reufiles:       dc.b $00        ;Amount of files successfully buffered to REU
                endif

;-------------------------------------------------------------------------------
; Filename (in short name mode) and hiscore filename
;-------------------------------------------------------------------------------

                if LONG_NAMES=0
filename:       dc.b "00*"
                endif

                if HISCORE_SUPPORT>0
scratch:        dc.b "S0:"
hiscorename:    dc.b "HI"
                endif

;-------------------------------------------------------------------------------
; Hiscores and runtime configuration variables.
;-------------------------------------------------------------------------------

                if HISCORE_SUPPORT>0
hiscores:       ds.b HISCORESIZE,0
                endif

                if SLOWLOAD_SUPPORT>0
usefastload:    dc.b $01                        ;If nonzero, fastloading will
                endif                           ;be used (on by default)
                if REU_SUPPORT>0
usereu:         dc.b $01                        ;If nonzero, REU will be
                endif                           ;detected and buffering files
                                                ;is possible (on by default)
                                                ;Is set to a negative value
                                                ;by INITREU if SuperRAM
                                                ;buffering is used!


;-------------------------------------------------------------------------------
; Disposable portion of loader (routines only needed when initializing)
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; INITLOADER
;
; Inits the loadersystem. Needs to be called only once in the beginning.
; If you don't want REU to be autodetected, set the "usereu" config variable
; to 0 before calling.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

initloader:     sta $d07f                       ;Disable SCPU hardware regs
                lda #$00
                sta fastloadstatus              ;Initial fastload status = off
                sta fileopen                    ;No file initially open

                if REU_SUPPORT>0
;-------------------------------------------------------------------------------
; INITREU
;
; REU initialization & memory size detection (called by INITLOADER)
; If REU isn't detected, tries to detects SuperRAM.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

initreu:        lda usereu                      ;Do not detect either REU
                beq ir_reuok                    ;or SuperRAM?
                ldx #$08
ir_loop:        lda ir_reutbl,x                 ;Load REU registers that
                sta c64base,x                   ;don't need to change
                dex
                bpl ir_loop
                lda status                      ;Read REU status
                lda #$00                        ;Write 0 to REU address 0
                sta reumemtop                   ;Assume there's no REU memory
                jsr ir_testwrite
ir_memtest:     inc reumemtop                   ;REU memory size detection;
                lda reumemtop                   ;Write the bank number to
                jsr ir_testwrite                ;REU memory
                sty loadbuffer                  ;Overwrite the byte in C64
                txa                             ;memory
                jsr ir_testread2                ;Read from address 0
                tax
                bne ir_memtestdone              ;If corrupted, exit
                jsr ir_testread
                cmp reumemtop                   ;If written value isn't
                bne ir_memtestdone              ;correct, exit
                jmp ir_memtest
ir_memtestdone: lda reumemtop                   ;REU must have at least
                cmp #$02                        ;128KB of working memory
                bcs ir_reuok

                bit $d0b2                   ; Check for hardware-regs disabled
                bmi ir_nosram               ; No? then no SCPU
                lda $d27f                   ; Get highest SRAM-Bank+1
                sec                         ; Subtract lowest SRAM-Bank
                sbc $d27d                   ; (both are 0 if no SRAM)
                cmp #$02                    ; at least 128KB free?
                bcc ir_nosram
                ror usereu                  ; indicate SRAM is present
                dc.b $2c
ir_nosram:      lda #$00
                sta reumemtop
ir_reuok:       rts

ir_testwrite:   sta loadbuffer
                ldy #%10110000
                lda reumemtop
ir_testcommon:  sta newreu2
                lda #$00
                sta newreu1
                jmp getreubuffer

ir_testread:    lda reumemtop
ir_testread2:   ldy #%10110001
                jsr ir_testcommon
                lda loadbuffer
                rts

ir_reutbl:      dc.b <loadbuffer, >loadbuffer ;C64 base
                dc.b 0,0,0                    ;REU base
                dc.w 256                      ;Transfer length
                dc.b 0                        ;IRQ mask
                dc.b 0                        ;Control register

;-------------------------------------------------------------------------------
; BUFFERTOREU
;
; Buffers a file into REU memory.
;
; Parameters: X,Y Filename address
; Returns: C=0 successful
;          C=1 error (A holds errorcode, $00 means out of REU memory)
;
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

buffertoreu:    lda reumemtop                   ;REU detected?
                beq btr_error
                jsr openfile
                lda fileopen                    ;If a file is already in REU,
                bmi btr_error                   ;do nothing
                lda reufreepage
                sta newreu1
                sta btr_filestartlo+1
                lda reufreepage+1
                sta newreu2
                sta btr_filestarthi+1
                cmp reumemtop                   ;Out of REU memory?
                bcs btr_error
                if SLOWLOAD_SUPPORT>0
                lda usefastload                 ;Using fastloading?
                bne btr_fastload
btr_slowload:   ldx #$02
btr_slowloadloop:
                jsr getbyte
                bcc btr_storeok
                tay                             ;Check for file not found
                bne btr_error
btr_storeok:    sta loadbuffer,x
                inx
                ldy fileopen                    ;Loop until file closed
                beq btr_slowloadend             ;or buffer full
                txa
                bne btr_slowloadloop
btr_slowloadend:sty loadbuffer
                dex
                stx loadbuffer+1
                jsr btr_writebuffer
                lda fileopen
                bne btr_slowload
                lda #$00
                sta loadbuffer+1
                sta loadbuffer+2                ;Statuscode OK
                jmp btr_lastblock
                else
                jmp btr_fastload
                endif

btr_writebuffer:lda newreu2
                cmp reumemtop
                bcs btr_wberror
                ldy #%10110000
                jmp getreubuffer
btr_wberror:    pla
                pla
btr_error:
btr_closefile:  jsr getbyte                     ;Read bytes from the file until
                bcc btr_closefile               ;closed (error code in A)
                rts

btr_fastload:   lda loadbuffer
                ora loadbuffer+1
                beq btr_error
btr_fastloadloop:
                jsr btr_writebuffer
                jsr fastload_fillbuffer
                lda loadbuffer
                ora loadbuffer+1
                bne btr_fastloadloop
                lda loadbuffer+2                ;Check for error in loading
                bne btr_error
btr_lastblock:  jsr btr_writebuffer
                lda newreu1
                sta reufreepage
                lda newreu2
                sta reufreepage+1
                lda #$00                        ;At last, write the directory
                sta newreu1                     ;entry
                sta newreu2
                ldx #$04
                lda reufiles
btr_finddirpos: asl                             ;Multiply filecount by 16
                rol newreu1                     ;to get position in the REU
                dex                             ;directory
                bne btr_finddirpos
                sta loadtempreg
                ldy #%10110001
                jsr getreubuffer
                ldx loadtempreg
                if LONG_NAMES>0
                ldy #$00
btr_copyname:   lda (destlo),y
                beq btr_copynamedone
                sta loadbuffer,x
                inx
                iny
                bne btr_copyname
btr_copynamedone:
                lda #$a0                        ;Put a name endmark
                sta loadbuffer,x
                ldx loadtempreg
                else
                lda filename
                sta loadbuffer,x
                lda filename+1
                sta loadbuffer+1,x
                endif
btr_filestartlo:lda #$00                        ;Store file startaddress in
                sta loadbuffer+14,x             ;REU
btr_filestarthi:lda #$00
                sta loadbuffer+15,x
                dec newreu1
                ldy #%10110000                  ;Write back directory buffer
                jsr getreubuffer
                inc reufiles                    ;Increase number of files
                clc                             ;Return with no error
                rts

                else
                rts
                endif

                if HISCORE_SUPPORT>0
;-------------------------------------------------------------------------------
; LOADHISCORES
;
; Loads the hiscore/configuration file.
;
; Parameters: -
; Returns: -
; Modifies: A,X,Y
;-------------------------------------------------------------------------------

loadhiscores:   ldy #$00                        ;Load to user-defined address
                jsr setlfsdevice
                jsr sethiscorename
                lda #$00
                ldx #<hiscores
                ldy #>hiscores
                if REU_SUPPORT>0
                jsr load                        ;Load hiscores
                lda usereu                      ;If a configuration with
                bpl lhs_ok                      ;SuperRAM-buffering was last
                lda #$01                        ;saved, let INITREU still
                sta usereu                      ;detect both REU & SuperRAM
lhs_ok:         rts                             ;this time
                else
                jmp load
                endif
                endif

                if REU_SUPPORT>0
;-------------------------------------------------------------------------------
; REU variables needed only when storing data to the REU.
;-------------------------------------------------------------------------------

reufreepage:    dc.w (REU_FILES+15)/16
reumemtop:      dc.b $00
                endif
