2-bit transfer protocol in diskdrive IRQ-loaders by Cadaver.txt

(21 KB) Pobierz
2-bit transfer protocol in diskdrive IRQ-loaders by Cadaver
-----------------------------------------------------------

This is a continuation of the previous IRQ-loader rant, that focused on a 1-bit
transfer protocol. The loader discussed here is very much like the previous one,
so only the changes in the protocol are explained in detail.

2-bit transfer, as mentioned in the previous rant, requires good synchronization
between the C64 and diskdrive. Once the transfer of a byte is fired up, the
1541 sends 2 bits at a time on both the CLK & DATA lines of the serial bus
without any waiting or handshaking.

What gives problems is that synchronization between the C64 & diskdrive can't
be cycle-exact; usually the diskdrive is waiting in a loop for the C64 to reply
before firing up the strictly timed transfer, so the timing might be off as
much as the length of this waiting loop.

The other problem is that the diskdrive CPU runs at 1Mhz, but the C64 runs
either slower (PAL) or faster (NTSC). This has to be taken into account also.
In fact it seems that when the transfer routine is coded in a certain way, the
difference between correct PAL & NTSC timing is only 1 clock cycle on the C64
side; the disk drive code doesn't have to be adjusted at all.

The drawbacks with this kind of 2-bit transfer are:
- Interrupts will be disabled during the transfer of a byte, so any raster
effects might be displaced.
- Sprites are not allowed onscreen (would steal CPU cycles and mess with the
timing.)
- Hitting RESTORE while loading will cause an NMI interrupt and also mess the
timing. There are two ways I can think of to handle this: Extend the transfer
protocol to have a resend option (the NMI interrupt will set a resend flag) or
disable NMIs by triggering a one-shot CIA2 interrupt but never acknowledging
the NMI. None of these are in use in the loader, it will just load incorrectly
if NMIs are occurring.

I thank Marko M??kel?? for his C64->diskdrive asynchronous protocol, drive init
code and original main drive loop, K.M/TABOO for inspiration on the badline
detection and MuOn for testing the transfer routines on a real NTSC machine.
The 2bit transfer code in this loader is coded by me but heavily inspired by
various game loadersystems; for example Technocop.

2-bit loader disk image and source


;COVERT BITOPS 2bit fastloader for Rant #9
;Based on:
;Marko M??kel??'s IRQ-loader
;- Drive init code
;- Drive main loop
;- Asynchronous C64->drive communication
;Technocop loader and other game loadersystems
;- Drive->C64 2-bit communication
;K.M/Taboo's 2bit loaders
;- Badline detection

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

bufferstatus    = $02
stackptrstore   = $03

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

                processor 6502
                org 2049

;Example main program. Inits the fastloader and loads a file using it. After-
;wards the drive can be used normally.

sys:            dc.b $0b,$08           ;Address of next instruction
                dc.b $0a,$00           ;Line number(10)
                dc.b $9e               ;SYS-token
                dc.b $32,$30,$36,$31   ;2061 as ASCII
                dc.b $00
                dc.b $00,$00           ;Instruction address 0 terminates
                                       ;the basic program

start:          jsr initfastload
                jsr initmusicplayback   ;Now that we can play music while
                ldx #"D"                ;loading, let's not forget it :-)
                ldy #"A"
                jsr fastload
                jsr stopmusicplayback
                rts

initmusicplayback:
                sei
                lda #<raster
                sta $0314
                lda #>raster
                sta $0315
                lda #50                 ;Set low bits of raster
                sta $d012               ;position
                lda $d011
                and #$7f                ;Set high bit of raster
                sta $d011               ;position (0)
                lda #$7f                ;Set timer interrupt off
                sta $dc0d
                lda #$01                ;Set raster interrupt on
                sta $d01a
                lda $dc0d               ;Acknowledge timer interrupt
                lda #$00
                jsr $1000
                cli
                rts

stopmusicplayback:
                sei
                lda #<$ea31
                sta $0314
                lda #>$ea31
                sta $0315
                lda #$00
                sta $d01a
                lda #$81
                sta $dc0d
                inc $d019
                lda #$00
                sta $d418
                cli
                rts

raster:         inc $d020
                jsr $1003
                dec $d020
                dec $d019
                jmp $ea31


;INITFASTLOAD
;
;Uploads the fastloader to disk drive memory and starts it.
;This routine is Marko M??kel??'s work, except for the 2-bit transfer
;preparations.
;
;Parameters: -
;Returns: -
;Modifies: A,X,Y

AMOUNT          = 32                    ;Bytes in one M-W command

The fastloader initialization code starts with PAL/NTSC detection. I didn't
want to rely on the value of $02a6 memory location so I implemented it with
raster-line based detection. This code measures the highest rasterline number
on the screen, and draws conclusions from that.

initfastload:   sei
                lda #$00
il_detectntsc:  ldx $d011              ;Get the biggest rasterline in the
                bmi il_detectntsc      ;area >= 256 to detect NTSC/PAL
il_detectntsc2: ldx $d011
                bpl il_detectntsc2
il_detectntsc3: cmp $d012
                bcs il_detectntsc4
                lda $d012
il_detectntsc4: ldx $d011
                bmi il_detectntsc3
                cli
                cmp #$20                ;PAL has 312 lines, but this check is
                bcc il_isntsc           ;somewhere in the middle...

For a PAL machine, the BPL instruction in the getbyte delay code (3 cycles,
takes the branch) is replaced with a BMI instruction (2 cycles, doesn't take
the branch)

                lda #$30                ;Adjust 2-bit fastload transfer
                sta fastload_delay      ;delay for PAL

The rest of the initialization is like in the 1-bit loader.

il_isntsc:      lda #<drvprog           ;Initialize selfmodifying code
                sta il_mwbyte+1
                lda #>drvprog
                sta il_mwbyte+2
                lda #<drive
                sta mwcmd+2
                lda #>drive
                sta mwcmd+1
il_mwloop:      jsr il_device           ;Set drive to listen
                ldx #lmwcmd - 1
il_sendmw:      lda mwcmd,x             ;Send M-W command
                jsr ciout
                dex
                bpl il_sendmw
                ldx #0
il_mwbyte:      lda drvprog,x             ;Send AMOUNT bytes of drive
                jsr ciout                 ;code
                inx
                cpx #AMOUNT
                bne il_mwbyte
                jsr unlsn               ;Unlisten starts the command
                lda mwcmd+2
                clc
                adc #AMOUNT
                sta mwcmd+2
                bcc il_nohigh
                inc mwcmd+1
il_nohigh:      lda il_mwbyte+1
                clc                     ;Move pointers
                adc #AMOUNT
                sta il_mwbyte+1
                tax
                bcc il_nohigh2
                inc il_mwbyte+2
il_nohigh2:     lda il_mwbyte+2
                cpx #<drvprogend
                sbc #>drvprogend
                bcc il_mwloop

                jsr il_device           ;Set drive to listen again
                ldx #lmecmd - 1
il_sendme:      lda mecmd,x             ;Send M-E command
                jsr ciout
                dex
                bpl il_sendme
                jmp unlsn               ;Unlisten starts the command

il_device:      lda fa
                jsr listen
                lda #$6f
                jmp second


;FASTLOAD
;
;Loads a file with fastloader. INITFASTLOAD must have been called first.
;Any normal KERNAL disk operations will cause the fastloader drive code to
;exit (as ATN line goes low) and after that, INITFASTLOAD has to be called
;again.
;
;Parameters: X: First letter of filename, Y: Second letter of filename
;Returns: C=0 OK, C=1 error
;Modifies: A,X,Y

fastload:       stx filename
                sty filename+1
                sta $d07a               ;SCPU to slow mode
                tsx                     ;Store stackpointer, needed when
                stx stackptrstore       ;finishing loading
                lda #$00                ;Reset buffer status
                sta bufferstatus
                ldx #$01                ;Byte counter.
fastload_sendouter:
                ldy #$08                ;Bit counter
fastload_sendinner:
                lsr filename,x          ;Rotate byte to be sent
                lda $dd00
                and #$ff-$30
                ora #$10
                bcc fastload_zerobit
                eor #$30
fastload_zerobit:
                sta $dd00
                lda #$c0                ;Wait for CLK & DATA low
fastload_sendack:
                bit $dd00
                bne fastload_sendack
...
Zgłoś jeśli naruszono regulamin