;*****************************************************************************
; 15 SECOND FORMAT ROUTINE
; Original: Mike J. Henry (Basement Boys / Fast Hack'Em)
; Modified: Alf Maier  (distributed on Quantum Link BBS, ~1986)
;*****************************************************************************
;
; C64 Kernal routines
OPEN_DEV              = $ED0C
CHKOUT                = $EDB9
CHROUT                = $FFD2
CIOUT                 = $EDDD
CIOUT2                = $FFA8
UNLSN                 = $EDFE
UNLSN2                = $FFAE
BASIN                 = $A560
LISTEN                = $FFB1
SECOND                = $FF93

; Zero page
SRC_PTR_LO            = $03 ; base address of the code block that is
SRC_PTR_HI            = $04 ; uploaded to the 1541 via M-W (lo/hi)
DST_PTR_LO            = $05 ; base address in 1541 RAM where code is
DST_PTR_HI            = $06 ; uploaded to (lo/hi)
DISK_ID_LO            = $12 ; disk ID char 1
DISK_ID_HI            = $13 ; disk ID char 2
TRACK                 = $22 ; current track
DATA_PTR              = $30 ; ptr to GCR data block for current sector
ZONE                  = $31 ; zone index (0-3) for ROM GCR routines
STRING_PTR_LO         = $35 ; string pointer for PRT_INL_STR lo byte
STRING_PTR_HI         = $36 ; string pointer for PRT_INL_STR hi byte
ID2                   = $39 ; disk ID byte 2 (copy for header build)
NSECTORS              = $43 ; sector count for current zone
DENSITY_BITS          = $44 ; density bits shifted for VIA2
BUMP_CTR              = $4A ; bump iteration counter
DEVICE                = $BA ; device number
STEP_DELAY            = $BB ; stepper settle delay counter
SECTOR                = $BC ; current sector number

* = $0801

; C64 BASIC loader
.word  $080B          ; next BASIC line ptr
.word  1984           ; BASIC line number
.byte  $9E            ; BASIC SYS token
.text  "2063"         ; SYS 2063 = SYS $080F
.byte  $00,$00,$00    ; BASIC end-of-program
.byte  $00,$00

; Upload code to the 1541.
; Uses 18 M-W CBM DOS commands, uploading to the $0500 buffer on the 1541
; $03/$04 = source ptr lo/hi = $0927
DRV_UPLOAD     LDA #<DRIVE_CODE
               LDX #>DRIVE_CODE
               STA SRC_PTR_LO
               STX SRC_PTR_HI
; $05/$06 = dest ptr lo/hi = $0500 (1541 buffer 0)
               LDA #$00
               LDX #$05
               STA DST_PTR_LO
               STX DST_PTR_HI
; Open device 8 command channel ($0F), LISTEN, send M-W command
UPLOAD_LOOP    LDA #$08
               JSR OPEN_DEV
               LDA #$6F
               JSR CHKOUT
               LDA #$4D ; 'M'
               JSR CIOUT
               LDA #$2D ; '-'
               JSR CIOUT
               LDA #$57 ; 'W'
               JSR CIOUT
               LDA DST_PTR_LO  ; upload address lo
               JSR CIOUT
               LDA DST_PTR_HI  ; upload address hi
               JSR CIOUT
               LDA #$1E ; byte count to upload (30 bytes)
               JSR CIOUT

; Send 30 bytes of drive code to 1541 via serial bus
               LDY #$00
SEND_BYTES     LDA (SRC_PTR_LO),Y
               JSR CIOUT
               INY
               CPY #$1E
               BCC SEND_BYTES

; send unlisten command to the 1541
END_CHUNK:     JSR UNLSN
               CLC
               LDA SRC_PTR_LO
               ADC #$1E
               STA SRC_PTR_LO 
               BCC L0862
; increment high byte if carry is set
               INC SRC_PTR_HI
               CLC
; increment dest pointer by 30
L0862          LDA DST_PTR_LO 
               LDX DST_PTR_HI
               ADC #$1E
               STA DST_PTR_LO
; increment dest high byte if carry is set
               BCC L086E
               INC DST_PTR_HI
; check: has dest high byte reached $07?
; (have we uploaded all 540 bytes to drive RAM) 
L086E          CPX #$07
; if not, loop back and send next chunk
               BCC UPLOAD_LOOP

UPLOAD_DONE_CHK:
; CMP #$9B: safety check on dest low byte (ensures last chunk complete)
; if low byte < $9B, send one more chunk
               CMP #$9B
               BCC UPLOAD_LOOP

; Upload complete. Print title screen via inline-string routine.
PRINT_TITLE    JSR PRT_INL_STR
.byte $93,$11,$20,$20,$20,$20,$20,$20   ; ..      
.byte $23,$23,$23,$20,$31,$35,$20,$53   ; ### 15 S
.byte $45,$43,$4F,$4E,$44,$53,$20,$46   ; ECONDS F
.byte $4F,$52,$4D,$41,$54,$49,$45,$52   ; ORMATIER
.byte $20,$23,$23,$23,$0D,$0D,$20,$41   ;  ###.. A
.byte $44,$41,$50,$54,$45,$44,$20,$46   ; DAPTED F
.byte $52,$4F,$4D,$20,$4D,$49,$4B,$45   ; ROM MIKE
.byte $20,$4A,$2E,$48,$45,$4E,$52,$59   ;  J.HENRY
.byte $20,$42,$59,$20,$41,$4C,$46,$20   ;  BY ALF 
.byte $4D,$41,$49,$45,$52,$00           ; MAIER.

PROMPT_DISKNAME JSR PRT_INL_STR
.byte $0D,$0D,$0D,$20,$20,$44,$49,$53   ; ...  DIS
.byte $4B,$4E,$41,$4D,$45,$2C,$49,$44   ; KNAME,ID
.byte $20,$3A,$20,$00                   ;  : .

; read the disk name and id from user and store in
; the keyboard buffer
GET_INPUT      JSR BASIN

PRINT_PLEASE_WAIT JSR PRT_INL_STR
.byte $0D,$20,$20,$20,$20,$20,$20,$20   ; .       
.byte $20,$20,$20,$20,$20,$50,$4C,$45   ;      PLE
.byte $41,$53,$45,$20,$57,$41,$49,$54   ; ASE WAIT
.byte $2E                               ; .
.byte $00                               ; NUL

; CBM DOS 2.6 built-in user command "UC:" = U3 = JMP $0500
; The 1541 ROM hard-codes U3 to jump to buffer 0 ($0500).
; No M-E command needed - "UC:" IS the trigger.
; The disk name and ID follow the "UC:" prefix in the command.
SEND_UC_CMD    LDA #$08
; LISTEN device 8
               STA $BA
               JSR LISTEN
; SECOND $6F (command channel)
               LDA #$6F
               STA $B9
               JSR SECOND
; Send 3 bytes from TBL_UC_CMD in reverse order
; Sends "UC:" to 1541 command channel
               LDX #$02
L090E          LDA TBL_UC_CMD,X
               JSR CIOUT2
               DEX
               BPL L090E

; Send keyboard buffer contents (disk name + "," + ID)
; Full command to 1541 = "UC:<diskname>,<id>"
; e.g. "UC:MY DISK,AB"
; Loop until null byte ($00) in buffer
SEND_KBUF      LDX #$00
L0919          LDA $0200,X
               BEQ UNLISTEN
               JSR CIOUT2
               INX
               BNE L0919
UNLISTEN       JMP UNLSN2

; Drive code: 540 bytes uploaded to 1541 RAM $0500-$071B via M-W
DRIVE_CODE:
        .byte $20,$A0,$06,$EA,$A9,$0A,$85,$BA
        .byte $78,$AD,$00,$1C,$09,$04,$8D,$00
        .byte $1C,$A9,$25,$85,$4A,$20,$4C,$05
        .byte $C6,$4A,$D0,$F9,$A2,$00,$20,$59
        .byte $05,$20,$76,$05,$A9,$EE,$8D,$0C
        .byte $1C,$20,$A1,$05,$AD,$00,$1C,$29
        .byte $FB,$8D,$00,$1C,$A9,$EC,$4C,$DB
        .byte $06,$58,$60,$A0,$02,$AE,$00,$1C
        .byte $E8,$20,$59,$05,$88,$D0,$F6,$E6
        .byte $22,$4C,$76,$05,$A0,$02,$AE,$00
        .byte $1C,$CA,$20,$59,$05,$88,$D0,$F6
        .byte $60,$8A,$29,$03,$85,$BB,$AD,$00
        .byte $1C,$29,$FC,$05,$BB,$8D,$00,$1C
        .byte $A9,$04,$85,$BB,$A2,$00,$CA,$D0
        .byte $FD,$C6,$BB,$D0,$F9,$60,$A5,$22
        .byte $20,$4B,$F2,$8A,$0A,$0A,$0A,$0A
        .byte $0A,$85,$44,$AD,$00,$1C,$29,$9F
        .byte $05,$44,$8D,$00,$1C,$60,$AD,$0C
        .byte $1C,$29,$1F,$09,$C0,$8D,$0C,$1C
        .byte $A9,$FF,$8D,$03,$1C,$8D,$01,$1C
        .byte $60,$A5,$22,$20,$4B,$F2,$85,$43
        .byte $20,$8E,$05,$A9,$FF,$8D,$01,$1C
        .byte $A9,$00,$85,$BC,$AA,$A8,$A5,$39
        .byte $99,$00,$03,$A5,$BC,$99,$02,$03
        .byte $A5,$22,$99,$03,$03,$A5,$13,$99
        .byte $04,$03,$A5,$12,$99,$05,$03,$A9
        .byte $0F,$99,$06,$03,$99,$07,$03,$A9
        .byte $00,$59,$02,$03,$59,$03,$03,$59
        .byte $04,$03,$59,$05,$03,$99,$01,$03
        .byte $18,$98,$69,$08,$A8,$E6,$BC,$A5
        .byte $BC,$C5,$43,$90,$C1,$98,$48,$E8
        .byte $8A,$9D,$00,$04,$E8,$D0,$FA,$A9
        .byte $4B,$8D,$00,$04,$A9,$03,$85,$31
        .byte $20,$30,$FE,$68,$A8,$88,$20,$E5
        .byte $FD,$20,$F5,$FD,$A9,$04,$85,$31
        .byte $20,$E9,$F5,$85,$3A,$20,$8F,$F7
        .byte $A9,$00,$85,$32,$A9,$FF,$8D,$01
        .byte $1C,$A2,$05,$50,$FE,$B8,$CA,$D0
        .byte $FA,$A2,$0A,$A4,$32,$50,$FE,$B8
        .byte $B9,$00,$03,$8D,$01,$1C,$C8,$CA
        .byte $D0,$F3,$84,$32,$A2,$08,$50,$FE
        .byte $B8,$A9,$55,$8D,$01,$1C,$CA,$D0
        .byte $F5,$A9,$FF,$A2,$05,$50,$FE,$B8
        .byte $8D,$01,$1C,$CA,$D0,$F7,$A2,$BB
        .byte $50,$FE,$B8,$BD,$00,$01,$8D,$01
        .byte $1C,$E8,$D0,$F4,$A0,$00,$50,$FE
        .byte $B8,$B1,$30,$8D,$01,$1C,$C8,$D0
        .byte $F5,$A9,$55,$A2,$08,$50,$FE,$B8
        .byte $8D,$01,$1C,$CA,$D0,$F7,$C6,$BC
        .byte $D0,$9A,$50,$FE,$B8,$50,$FE,$B8
        .byte $20,$00,$FE,$A5,$22,$C9,$23,$F0
        .byte $06,$20,$3B,$05,$4C,$A1,$05,$60
        .byte $20,$E5,$C1,$D0,$05,$A9,$34,$4C
        .byte $C8,$C1,$88,$88,$8C,$7A,$02,$AD
        .byte $8A,$02,$D0,$F1,$A2,$00,$A9,$8D
        .byte $20,$68,$C2,$E8,$8E,$78,$02,$20
        .byte $12,$C3,$A9,$00,$85,$7F,$20,$00
        .byte $C1,$AC,$7B,$02,$B9,$00,$02,$85
        .byte $12,$B9,$01,$02,$85,$13,$A9,$01
        .byte $85,$22,$60,$8D,$0C,$1C,$58,$20
        .byte $05,$F0,$4C,$56,$EE
; This concludes the actual 1541 drive code, but
; note that code below is also uploaded to the 1541
; as overflow in the DRV_UPLOAD loop even though it's
; not used on the 1541.

;print an inline string
PRT_INL_STR    PLA      ; pull return address off the stack
               STA STRING_PTR_LO
               PLA
               STA STRING_PTR_HI
; advance past JSR instruction to first string byte
               LDY #$00
               INC STRING_PTR_LO
               BNE L0B1A
               INC STRING_PTR_HI
L0B1A          LDA (STRING_PTR_LO),Y
               BEQ L0B29
; next char
               JSR CHROUT
               INC STRING_PTR_LO
               BNE L0B1A
               INC STRING_PTR_HI
               BNE L0B1A
; move past null to first instruction after string
L0B29          INC STRING_PTR_LO
               BNE L0B2F
               INC STRING_PTR_HI
; return to instruction after string
L0B2F          JMP (STRING_PTR_LO)
               BRK

; UC command bytes, in reverse order. :CU (for sending UC:)
; The trainling $FF byte exists in the original. I don't know why.
TBL_UC_CMD .byte $3A,$43,$55,$FF
