Marko's IRQ loader routine

From: Cameron Kaiser (spectre_at_calvin.ptloma.edu)
Date: 1998-12-28 19:51:25

I'm tinkering with Marko's IRQ loader, which works great, except for
one thing: my IRQ routine also changes $dd00. I've patched my IRQ routine so
that it only messes with bits 1 and 0, the VIC-II banking bits, but the
loader still causes the screen to flicker -- it seems like it assumes $dd00
isn't changing. I made the changes below (in dasm format) but it just freezes
up. Any ideas? Is it timing? (Look for lines with VBMODE in them for my
changes -- I've made them conditional if VBMODE = 1.)

--
;----------------------------------------------------------------------
; Synchronous 1540/1541/1570/1571 fastloader
; Copyright © 1996 Marko Mäkelä <Marko.Makela@HUT.FI>
;
; VBMODE compatibility patch by Cameron Kaiser <ckaiser@oa.ptloma.edu>
; Copyright 1998 Cameron Kaiser
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;----------------------------------------------------------------------
; Init: jsr init
; Load: ldx #"A" ;first char of name
;       ldy #"B" ;second char of name
;       jsr irqload
;       ; C=status: 0=ok, 1=error
;----------------------------------------------------------------------

target eqm c64 ; choose the target system
vic20 = 1       ; Commodore VIC-20
c64   = 2       ; Commodore 64
c128  = 4       ; Commodore 128
c16   = 8       ; The Commodore 264 Series (C16, C116, plus/4)

; Kaiser's patch for proper VIC-II bank handling (64 only)
VBMODE = 1	; 1 = yes, do try to handle this right
		; 0 = no

START = $cc00   ; and the start address
RETRIES = 5     ; amount of retries when reading a sector

LEDFLASH = 2    ; LED flashing level:
                ; 0 = normal (LED constantly on while loading a file)
                ; 1 = LED glows on and off while waiting for a command
                ; 2 = LED on only while reading sectors
                ; 3 = 1 + 2

;---------------------------------------
; source code begins
; no user-modifiable routines inside :-)

#processor 6502

; include the ROM definitions

#if target & c16
#include "include/c16rom.lib"
#else
; #include "include/cbmrom.lib"
ciout = 65448
listn = 65457
secnd = 65427
unlsn = 65454
sal = 172
fa = 186
#endif

AMOUNT = $20    ; amount of data bytes to transfer with one M-W command
ESCBYTE = $ac   ; the escape char used in the transfers

; set the I/O constants and the variables

#if target & vic20
iecport1 = $912c
dato = 32
clko = 2
iecport2 = $911f
atno = 128
clki = 1
dati = 2
#endif

#if target & (c64 | c128)
iecport1 = $dd00
iecport2 = iecport1
atno = 8
clko = 16
dato = 32
clki = 64
dati = 128
#endif

#if target & c16
iecport1 = 1
iecport2 = iecport1
dato = 1
clko = 2
atno = 4
clki = 64
dati = 128
#endif

; declare the zeropage variables

store  = sal    ; temporary byte storage

#org START

init:
; initialize the self-modifying parts of the code
  lda #<drvcode
  sta mwbyte$ + 1
  lda #>drvcode
  sta mwbyte$ + 2
  lda #<drive
  sta mwcmd$ + 2
  lda #>drive
  sta mwcmd$ + 1
; send the m-w command to write the data
mwloop$:
  jsr inidev$
  ldx #lmwcmd$ - 1
smwcmd$:
  lda mwcmd$,x
  jsr ciout
  dex
  bpl smwcmd$

; send the actual data bytes
  ldx #0
mwbyte$:
  lda drvcode,x
  jsr ciout
  inx
  cpx #AMOUNT
  bne mwbyte$

; complete the command
  jsr unlsn

; update the addresses
  clc
  lda #AMOUNT
  adc mwbyte$ + 1
  sta mwbyte$ + 1
  bcc noupdhi1$
  clc
  inc mwbyte$ + 2
noupdhi1$:

  lda #AMOUNT
  adc mwcmd$ + 2
  sta mwcmd$ + 2
  tax
  lda #0
  adc mwcmd$ + 1
  sta mwcmd$ + 1
  cpx #<edrvcode
  sbc #>edrvcode
  bcc mwloop$

; send m-e to start the routine
  jsr inidev$
  ldx #lmecmd$ - 1
sendcmd$:
  lda mecmd$,x
  jsr ciout
  dex
  bpl sendcmd$
; perform the command
  jmp unlsn

; subroutine: make the current drive listen

inidev$:
  lda fa
  jsr listn
  lda #$6f
  jmp secnd

; the m-w command backwards

mwcmd$:
  dc.b AMOUNT,>drive,<drive,"W-M"
lmwcmd$ = . - mwcmd$

; the m-e command backwards

mecmd$:
  dc.b >drive,<drive,"E-M"
lmecmd$ = . - mecmd$


;---------------------------------------
; the actual irq loader

irqload:
; this is not going to work if the irq routine is varying the vic-ii bank,
; so don't bother if VBMODE is on because we need to check on every call then.
#if target & (c64|c128) && VBMODE
  nop	 ; just a placeholder :-)
#else
  lda iecport1
  and #255 - dato - clko
  sta iec1d1a$  ; CLK=1, DATA=1
  sta iec1d1b$
  eor #clko
  sta iec0d1a$  ; CLK=0, DATA=1
  sta iec0d1b$
#endif

  txa           ; send the file name's first character
  jsr putbyt$
  tya           ; send the file name's second character
  jsr putbyt$

  jsr getbyt$   ; get the start address
  tay
  jsr getbyt$
  sta adrhi$

loadloop$:
  jsr getbyt$   ; get next file byte, exit on completion
adrhi$ = . + 2
  sta $100,y    ; store it
  iny
  bne loadloop$
  inc adrhi$
  jmp loadloop$

;---------------------------------------
; getbyt$: get a byte, interpret the escape codes

getbyt$:
  jsr getbits$
  cmp #ESCBYTE
  bne getdone$
  jsr getbits$  ; escape char fetched, get another byte
  cmp #ESCBYTE  ; another escape char: it is a literal
  beq getdone$
  cmp #1        ; Transfer finished. 0=ok, nonzero=error.
  pla           ; Set the C flag accordingly.
  pla           ; discard the return address
getdone$:
  rts

; getbits$: get a byte

getbits$:
  ldx #8        ; counter: get 8 bits
getbit$:
  lda iecport2
  and #dati | clki
  eor #dati | clki
  beq getbit$   ; wait for CLK==low || DATA==low

#if dati == 128
  asl           ; Carry = DATA==low
#else
#if dati < clki
  and #dati
#endif
  cmp #dati
#endif

iec0d1a$ = . + 1
#if target & (c64|c128) && VBMODE
  lda $dd00
  and #3
  ora #252 ^ dato
#else
  lda #255 - dato
#endif
  bcs gskip$
  eor #dato | clko
gskip$:
  sta iecport1  ; acknowledge the bit
  ror store     ; store the data

  lda #dati | clki
wgetack$:
  bit iecport2
  beq wgetack$  ; wait for CLK==high || DATA==high

iec1d1a$ = . + 1
#if target & (c64|c128) && VBMODE
  lda $dd00
  and #3
  ora #252 ^ clko ^ dato
#else
  lda #255 - clko - dato
#endif
  sta iecport1  ; raise CLK and DATA
  dex
  bne getbit$   ; loop until all bits are received
  lda store
  rts

; putbyt$ puts a byte

putbyt$:
  sta store
  ldx #8        ; counter: send all 8 bits
putbit$:
  lsr store     ; read a bit
iec0d1b$ = . + 1
#if target & (c64|c128) && VBMODE
  lda $dd00
  and #3
  ora #252 ^ dato
#else
  lda #255 - dato
#endif
  bcc pskip$
  eor #dato | clko
pskip$:
  sta iecport1  ; send the data

  lda #dati | clki
wputack1$:
  bit iecport2
  bne wputack1$ ; wait for CLK==DATA==low

iec1d1b$ = . + 1
#if target & (c64|c128) && VBMODE
  lda $dd00
  and #3
  ora #252 ^ clko ^ dato
#else
  lda #255 - clko - dato
#endif
  sta iecport1  ; set DATA=CLK=high
wputack2$:
  lda iecport2
  and #dati | clki
  eor #dati | clki
  bne wputack2$ ; wait for CLK==DATA==high
  dex
  bne putbit$   ; loop until all bits are sent
  rts

;---------------------------------------
; the drive code

drvcode:

#rorg $500

acsbf   = $01 ;access to buffer 1
trkbf   = $08 ;track of buffer 1
sctbf   = $09 ;sector of buffer 1
iddrv0  = $12 ;id of drive 0
id      = $16 ;id
datbf   = $14 ;databuffer

buf     = $0400 ;sector buffer

via1pb  = $1800
via2pb  = $1c00

;---------------------------------------

drive:
  cld
driveloop:
  cli           ; interrupts enabled until first sector read
#if !(LEDFLASH & 1)
  lda via2pb
  and #$f7      ; led off
  sta via2pb
#endif

  jsr recv$
  sta temp1$    ; get the file name, first char
  jsr recv$
  sta temp2$    ; second char
#if !(LEDFLASH & 2)
  lda #8
  ora via2pb
  sta via2pb    ; led on
#endif

  ldx #18
  ldy #1        ; read the disk directory (track 18, sector 1)
dirloop$:
  stx trkbf
  sty sctbf
  jsr readsect$ ; read the sector
  bcs errquit$  ; quit if it could not be read

  ldy #$02
nextfile$:
  lda buf,y     ; check file type
  and #$83
  cmp #$82      ; must be PRG
  bne notfound$

  lda buf+3,y   ; check the first two characters
  cmp temp1$
  bne notfound$

  lda buf+4,y
  cmp temp2$
  beq found$

notfound$:
  tya
  clc
  adc #$20
  tay
  bcc nextfile$

  ldy buf+1     ; get next sector
  ldx buf       ; and track
  bne dirloop$  ; keep trying until the last directory block has been searched

  ; file not found: fall through

errquit$:
  ldx #ESCBYTE  ; send the escape byte followed by 1 to notify the computer
  jsr send$
  ldx #1
  jsr send$
  jmp driveloop

found$:
  lda buf+1,y   ; get the track and sector numbers
  sta trkbf
  lda buf+2,y
  sta sctbf

nextsect$:
  jsr readsect$
  bcs errquit$  ; quit if the sector could not be read
  ldy #$00
  lda buf+1     ; store the track and sector of next block
  sta sctbf
  lda buf
  sta trkbf
  bne notlast$  ; if the track is nonzero, this wasn't the last sector

  ldy buf+1     ; last sector: get sector length
  iny
notlast$:
  sty temp1$

  ldy #2        ; skip the track and sector when sending the buffer

sendbuf$:       ; send the buffer contents to the computer
  ldx buf,y
  cpx #ESCBYTE
  bne noesc$

  jsr send$     ; escape the escape character
  ldx #ESCBYTE

noesc$:
  jsr send$
  iny
  cpy temp1$    ; were all bytes of the block sent?
  bne sendbuf$

  lda buf
  bne nextsect$ ; loop until all sectors are loaded

finish$:
  ldx #ESCBYTE  ; send the escape byte followed by 0 to notify the computer
  jsr send$
  ldx #0
  jsr send$
  jmp driveloop

;---------------------------------------
; readsect$: read a sector

readsect$:
#if LEDFLASH & 2
  lda #8
  ora via2pb
  sta via2pb    ; turn the LED on
#endif
  ldy #RETRIES  ; load the retry count
  cli           ; enable interrupts, so that the command will be executed
retry$:
  lda #$80
  sta acsbf     ; code for reading the sector
poll1$:
  lda acsbf     ; wait for the command to complete
  bmi poll1$

  cmp #1
  bne noexit$
#if LEDFLASH & 2
  lda #$f7
  and via2pb
  sta via2pb    ; turn the LED off
#endif
  clc
  sei           ; disable interrupts again to make the program faster
  rts           ; success: exit the loop

noexit$:
  dey           ; decrement the retry count
  bmi error$    ; quit if there were too many retries

  cpy #RETRIES / 2
  bne skipcode$

  lda #$c0
  sta acsbf     ; half the retries left: knock the head (seek track 1)

skipcode$:
  lda id        ; tolerate disk id changes
  sta iddrv0
  lda id+1
  sta iddrv0+1

poll2$:
  lda acsbf     ; wait for the command to complete
  bmi poll2$
  bpl retry$    ; branch always

error$:
#if LEDFLASH & 2
  lda #$f7
  and via2pb
  sta via2pb    ; turn the LED off
#endif
  sec
  sei
  rts

; send$ sends the X register contents. datbf is used as temporary storage.

send$:
  stx datbf
  ldx #8        ; send 8 bits
; sendbit$ sends a bit
sendbit$:
  lsr datbf     ; read next bit
  lda #2        ; prepare for CLK=high, DATA=low
  bcs sskip$
  lda #8        ; prepare for CLK=low, DATA=high
sskip$:
  sta via1pb    ; send the data

sgetack$:
  lda via1pb    ; wait for CLK==DATA==low
  and #5
  eor #5
  bne sgetack$
  sta via1pb    ; set CLK=DATA=high

  lda #5
swait$:
  bit via1pb
  bne swait$    ; wait for CLK==DATA==high

  dex
  bne sendbit$  ; loop until all bits have been sent
  rts

;---------------------------------------
; recv$ receives a byte to A. datbf is used as temporary storage.

recv$:
#if LEDFLASH & 1
  ldy #0        ; LED brightness (0=dim, 255=lit)
  tsx
fincr$:
  jsr doflash$
  ldy datbf
  iny
  bne fincr$
fdecr$:
  dey
  jsr doflash$
  ldy datbf
  bne fdecr$
  beq fincr$

doflash$:
  sty datbf     ; store the counter for LED flashing
  lda #$f7
  and via2pb
  sta via2pb    ; turn the LED off
  jsr fdelay$   ; perform the delay
  lda #8
  ora via2pb
  sta via2pb    ; turn the LED on
  lda datbf
  eor #$ff
  tay           ; fall through

fdelay$:
  lda #$85
  and via1pb    ; wait for any signal from the bus
  bne flashdone$
  iny
  bne fdelay$
  rts

flashdone$:
  lda #$f7
  and via2pb
  sta via2pb    ; turn the LED off
  txs           ; discard the return address
#endif

  ldx #8        ; counter: receive 8 bits
recvbit$:
  lda #$85
  and via1pb    ; wait for CLK==low || DATA==low
  bmi gotatn$   ; quit if ATN was asserted
  beq recvbit$
  lsr           ; read the data bit
  lda #2        ; prepare for CLK=high, DATA=low
  bcc rskip$
  lda #8        ; prepare for CLK=low, DATA=high
rskip$:
  sta via1pb    ; acknowledge the bit received
  ror datbf     ; and store it
rwait$:
  lda via1pb    ; wait for CLK==high || DATA==high
  and #5
  eor #5
  beq rwait$
  lda #0
  sta via1pb    ; set CLK=DATA=high

  dex
  bne recvbit$  ; loop until all bits have been received
  lda datbf     ; read the data to A
  rts

gotatn$:
  pla           ; If ATN gets asserted, exit to the operating system.
  pla           ; Discard the return address.
  cli           ; Enable the interrupts.
  rts

temp1$ = .
temp2$ = . + 1

edrvcode:
#rend



-- 
Cameron Kaiser *** http://calvin.ptloma.edu/~spectre/ *** spectre@ptloma.edu
"Please dispose of this message in the usual manner." -- Mission: Impossible
-
This message was sent through the cbm-hackers mailing list.
To unsubscribe: echo unsubscribe | mail cbm-hackers-request@dot.tcm.hut.fi.

Archive generated by hypermail 2.1.1.