;###############################################################################
;#
;# ACME cross-assembler:     acme -f plain -o T64Loader_V5.prg T64Loader_V5.asm
;#
;###############################################################################

                add_RAMSTART    = $0200				; the RAM part of the loader goes here
                
                zp_pt_DIR       = $bb				; pointer to our directory entry after we finished the search

                zp_pt_DIRSEARCH = $02				; BEFORE actual load re-use for directory search                
                zp_TEMP   		= $02

                
                ; Needed offsets in the T64 Directory
                add_DIRSTART  = add_T64START +$40	; t64 starts at $8x00, first 32 bytes are header
                NUMBEROFFILES   = add_T64START +$22	; Number of directory entries
                off_LOADADDR  = $02				; Where to load the file unless secondary address!
                off_ENDADDR   = $04				; End-address
                off_FILENAME  = $10				; Filename starts here padded with Space
                off_T64       = $08				; Start of ROM in file (PRG 2-byte Header has been chopped off!)


                *=$8000								; ROM starts at $8000

                !word add_COLDSTART
                !word add_WARMSTART					; points to Loader Install - can be used as entry point for other software

                !by $c3,$c2,$cd, $38,$30			; Cartridge Signature

tab_VICINIT:    !by $00,$00,$00,$00,$00,$00,$00,$00   ; $d000-$d007
                !by $00,$00,$00,$00,$00,$00,$00,$00   ; $d008-$d00f
                !by $00,$0b,$00,$00,$00,$00,$c8,$00   ; $d010-$d017
                !by $15,$71,$f0,$00,$00,$00,$00,$00   ; $d018-$d01f
                !by $00,$00,$01,$02,$03,$f4,$f0,$f1   ; $d020-$d027
                !by $f2,$f3,$f4,$f5,$f6,$f7,$fc       ; $d028-$d02e

add_COLDSTART:  sei
                ldx #$ff
                txs									; reset stackpointer
                cld									; clear D-flag
                
                lda #8								; allow VIC access
                sta $d016
                
                lda #$0								; refresh RAM (see RAM-datasheet)
                tax
-               sta $0002, x						; $0002-$03ff = 0
                sta $0100, x
                sta $0200, x
                sta $0300, x
                dex
                bne -
                
                ldx #$2f							; VIC init from table
-               lda tab_VICINIT, x
                sta $d000, x
                dex
                bpl -

                lda #$37							; init $01 and then! $00
                sta $01
                lda #$2f
                sta $00
                
                jsr $ff84							; cia init und $00/$01 init. ($fda3)
                                   
                ldy #$a0
                jsr $fd8c							; set vectors $0282-$0284, $0288 
                jsr $e453							; set vectors $0300-$030b
                jsr $e3bf							; set vectors $0310-$0312
                jsr $fd15							; set vectors $0314-$0333
                jsr $e51b							; init zp for screen and keyboard ($cc-$f5 without $ce, $d0, $d2, $d4, $d7, $d8) 
                
                lda #3								; current output device = screen
                sta $9a
                
                jsr sub_COPYLOADER
  
                lda add_DIRSTART + off_FILENAME	; Autostart the first file when Filename starts with !
                cmp #$21
                bne sub_COPYLOADER
  
                lda add_DIRSTART + off_FILENAME + 4
                jsr sub_PET2BYTE  
                sta add_sm_JUMP + 1
                lda add_DIRSTART + off_FILENAME + 3
                jsr sub_PET2BYTE
                asl
                asl
                asl
                asl
                adc add_sm_JUMP + 1
                sta add_sm_JUMP + 1
                
                lda add_DIRSTART + off_FILENAME + 2
                jsr sub_PET2BYTE
                sta add_sm_JUMP + 2
                lda add_DIRSTART + off_FILENAME + 1
                jsr sub_PET2BYTE
                asl
                asl
                asl
                asl
                adc add_sm_JUMP + 2
                sta add_sm_JUMP + 2
                
				jmp ($0330)							; Load the file with our loader


sub_PET2BYTE:   sec
                sbc #$30
                cmp #$0a
                bcc +
                sbc #$07
+               rts



add_WARMSTART:

sub_COPYLOADER: ldy #add_ENDOFLOADER - 1 - add_RAMSTART
-               lda add_ROMLOADER,Y
                sta add_RAMSTART,Y
                dey
                bpl -

                lda #<add_RAMSTART						; Set loadvector to our loader
                sta $0330
                lda #>add_RAMSTART
                sta $0331
                rts

; ----- ROM-Loader ----

 
sub_COPYINIT:   lda $b7               ; when name has length zero, replace with first file
                bne +
                inc $b7
                lda add_DIRSTART + off_FILENAME
                sta add_FILENAME

				lda #$4c						; JMP-Opcode schreiben
				!byte $2c
+				lda #$60						; RTS-Opcode schreiben
				sta add_sm_JUMP					

NOTFIRST:       lda #>add_DIRSTART
                sta zp_pt_DIRSEARCH + 1
                lda #<add_DIRSTART
                clc
                adc #$10
                sta zp_pt_DIRSEARCH
                bcc +
                inc zp_pt_DIRSEARCH + 1
+ 
NAMECHECK:      ldy $b7				; check filenames starting at last character as T64 pads with spaces
                dey
-               lda (zp_pt_DIRSEARCH), Y
                cmp add_FILENAME, Y
                bne NEXTFILE
                dey
                bpl -
                jmp FOUNDFILE
  
NEXTFILE:       lda zp_pt_DIRSEARCH
                clc
                adc #$20
                sta zp_pt_DIRSEARCH
                bcc +
                inc zp_pt_DIRSEARCH + 1
+               jmp NAMECHECK


;-----------------------------------------------
  
FOUNDFILE:      lda zp_pt_DIRSEARCH		; Set pointer to directory entry
                sec 
                sbc #$10
                sta zp_pt_DIR
                lda zp_pt_DIRSEARCH + 1
                sbc #$00
                sta zp_pt_DIR + 1

                ldy #off_LOADADDR		; Get load address
                lda (zp_pt_DIR), Y
                sta sm_WRITEBYTE + 1
                iny
                lda (zp_pt_DIR), Y
                sta sm_WRITEBYTE + 2

                ldy #off_ENDADDR		; Write end address
                lda (zp_pt_DIR), Y
                sta sm_ENDCOUNTLO + 1
                iny
                lda (zp_pt_DIR), Y
                sta sm_ENDCOUNTHI + 1 

;########################################################################################

				; Get STARTADDRESS in ROM (FROM:) by converting 3-Byte position into bank and position
                ; The startaddress inside the bank is written directly into the copy routine which is self-modifying

GETSTART:       ldy #off_T64						; write low byte unchanged
                lda (zp_pt_DIR), Y
                sta sm_READBYTE + 1    

                iny									; get mid byte
                lda (zp_pt_DIR), Y
                clc
                adc #>(add_T64START - $8000)		; add loader size
                pha									; A --> stack

+               ror									; division / 32 with carry
                lsr
                lsr
                lsr
                lsr

                clc
                sta zp_TEMP							; write bank
				
                pla									; A <-- Stack 

                and #$1f
                ora #$80
                sta sm_READBYTE + 2					; write offset in ROM

                iny									; get high byte (0...15)
                lda (zp_pt_DIR), Y
                asl									; multiplication with 8
                asl
                asl

                clc                             
                adc zp_TEMP							; add banks 
				tax									; return x = current bank

				rts

;########################################################################################

add_ROMLOADER:  !PSEUDOPC add_RAMSTART {

add_RAMLOADER:  php
                pla
                and #$ee
                pha						; Safe Flags on stack (Carry = 0 ; Break = 0)
				
                sei
                lda $01					; Safe $01 on stack
				pha

                lda #$37
                sta $01
				lda #$00				; Bank = 0
				sta $de00

COPYNAME:       ldy $b7				    ; Copy filename into RAM
				beq +
-               inc $01
				lda ($bb), y
				dec $01
                sta add_FILENAME, y
                dey
                bpl -               
+				
				jsr sub_COPYINIT
                
                stx $de00				; Write bank  		
COPYLOOP:         	
sm_READBYTE:	lda $8000				; Read (selfmodify)

				inc $01
sm_WRITEBYTE:   sta $0801				; Write (selfmodify)
				dec $01

                inc sm_READBYTE + 1		; Increment read address
                bne +
                inc sm_READBYTE + 2
                lda sm_READBYTE + 2
                cmp #$a0
                bne +
				                    
				inx						; If end of bank then bank+1
                stx $de00
                lda #$80				; Set H-byte to #$80
                sta sm_READBYTE + 2

+               inc sm_WRITEBYTE + 1	; Increment write address
                bne +
                inc sm_WRITEBYTE + 2

+               lda sm_WRITEBYTE + 1	; end of file ?
                sta $ae
sm_ENDCOUNTLO:  cmp #$00
                bne COPYLOOP
                lda sm_WRITEBYTE + 2
                sta $af				
sm_ENDCOUNTHI:  cmp #$00
                bne COPYLOOP

                lda #$80				; switch off Magic Cart
                sta $DE00    

				pla
                sta $01					; restore $01
                plp						; restore flags

add_sm_JUMP:    jmp $1000				; will be modified to the real JMP address for autoload

add_ENDOFLOADER:
add_FILENAME:   !tx "                "	; Space for 16 chars of filename

                }

                !align 255, 0, 0		; fill up the next page (256 byte) with #0
add_T64START: