  .processor 6502
  .include "options.inc"

#if target & c128
host	= 128
#endif
#if target & c64
host	= 64
#endif
#if target & vic20
host	= 20
#endif
#if target & (pet3001 | pet4001)
host	= 201	; want 2001 but it must fit in a byte
#endif

#if target & (c128 | c64)
#if ramexp & piaexp
pia	= $d7f0 ; the PIA base address.  See also the definition "bank".
#endif
#if ramexp & reuexp
reu	= $df00 ; the REU base address.  See also the definition "bank".
reubmin = $10	; smallest bank number that refers to the REU banks
#endif
#endif		; target & (c128 | c64)

; The machines with a VIA that use a VIA control line for handshaking
; must reset the interrupt flag before it can be used again.

clearviaifr = target & (vic20 | pet3001 | pet4001)

; The following constant tells if the cable uses the PA2 handshaking line

pa2_used = cable & (pc64 | prlink | prlink88)

  seg MAIN
  .org prsrv

#if target & (vic20 | c64 | c128)
strval	= $10	; strobe bit value on the Vic-20/C64/C128

start	= $ac	; some memory locations
end	= $ae
cinv	= $314
#endif		; target & (vic20 | c64 | c128)

#if cable & (pc64 | c64net | transnib)
#if target & (pet3001 | pet4001)
stemp	= $bd	; memory place that holds the byte that will be received
#else
stemp	= $a7	; memory place that holds the byte that will be received
#endif
#endif

#if target & c128
bstart	= $2d	; start of basic program text
bend	= $1210 ; end of basic program text

bank	= $a9	; temporary variable that holds the memory bank
stack	= $105	; offset to the stack while in interrupt

peek	= $2a2
peekptr = $2aa
poke	= $2af
pokeptr = $2b9

linkprg = $4f4f
basrun	= $5aa6

ackval	= 4
ack	= $dd00
data	= $dd01
ddr	= $dd03
strobe	= $dd0d
#endif		; target & c128

#if target & c64
bstart	= $2b	; start of basic program text
bend	= $2d	; end of basic program text
#if ramexp
bank	= $a9	; temporary variable that holds the memory bank
#else
bank	= none	; non-banked systems
#endif
blnsw	= $cc
crsw	= $d0

stack	= $104	; offset to the stack while in interrupt

clr	= $a659
linkprg = $a533
stxpt	= $a68e
newstt	= $a7ae

ackval	= 4
ack	= $dd00
data	= $dd01
ddr	= $dd03
strobe	= $dd0d
#endif		; target & c64

#if target & vic20
bstart	= $2b	; start of basic program text
bend	= $2d	; end of basic program text
bank	= none
blnsw	= $cc
crsw	= $d0

stack	= $104	; offset to the stack while in interrupt

clr	= $c659
linkprg = $c533
stxpt	= $c68e
newstt	= $c7ae

ackval	= $20
ack	= $911c
data	= $9110
ddr	= $9112
strobe	= $911d
#endif		; target & vic20

#if target & (pet3001 | pet4001)
start	= $c7	;; the PET series
end	= $c9
cinv	= $0090

bstart	= $28	; start of basic program text
bend	= $2a	; end of basic program text
blnsw	= $a7
crsw	= $ac

#if ramexp & pet96
bank  = $bf	; temporary variable that holds the memory bank
latch = $fff0	; write-only register
#else
bank	= none	; non-banked systems
#endif

stack = $104	; offset to the stack while in interrupt

ackval	= $20	; CB2 value bit when set to manual control
ack	= $e84c ; VIA CRB
data	= $e84f ; VIA PA without handshake
ddr	= $e843 ; VIA DDRA
strval	= $02	; VIA CA1 bit in IFR
strobe	= $e84d ; VIA IFR
#endif		; target & (pet3001 | pet4001)

#if target & pet4001	; for BASIC 4.0
clr	= $b5e9
linkprg = $b4b6
stxpt	= $b622
newstt	= $b74a
#endif
#if target & pet3001	; for BASIC 2.0
clr	= $c572
linkprg = $c442
stxpt	= $c5a7
newstt	= $c6c4
#endif

cmdinfo = 0	; code for requesting machine type info
cmdload = 1	; code for loading
cmdsave = 2	; code for saving
cmdjump = 3	; code for jumping to an address
cmdrun	= 4	; code for running a BASIC program

mystart:	; A jump table for external programs
  jmp install		; Installs the prserver wedge.
  jmp deinstall 	; Removes the prserver wedge.
  jmp send_switch	; Switches to send configuration, and sends a byte.
  jmp send		; Sends a byte assuming send configuration.
  jmp receive_switch	; Switches to receive configuration, and receives a byte.
  jmp receive		; Receives a byte assuming receive configuration.
  jsr install		; Reinstalls the prserver wedge and
#if target & c128	; continues with the previous program.
  jmp $ff33
#else
  pla
  tay
  pla
  tax
  pla
  rti
#endif		; target & c128

install:
  sei
  lda cinv	; check the original IRQ vector
  ldx cinv+1
  cmp #<irq
  bne irqinit
  cpx #>irq
  beq skipirq
irqinit:	; if it was different from our irq wedge, install the wedge
  sta oldirq	; first save the old IRQ vector
  stx oldirq+1
  lda #<irq	; and then install ours
  sta cinv
  lda #>irq
  sta cinv+1
skipirq:
#if ramexp & piaexp
#if target & c128
  lda #$3e
  sta $ff00
#endif
  ldx #11	; initialize the PIA
0$:
  lda piatable-1,x
  sta pia,x
  dex
  bne 0$
#endif		; ramexp & piaexp
#if cable & (prlink | prlink88 | pc64)
#if target & vic20
  lda #$ef
  and ack
  sta ack	; set CB1 to trigger on falling edge
#endif
#if target & (pet3001 | pet4001)
  lda ack
  and #%11111110; set CA1 to trigger on falling edge
  ora #%11100000; set CB2 to output with manual control
  sta ack
#endif
#endif		; cable & (prlink | prlink88 | pc64)
#if cable & transnib
  lda #$40	; prepare for input: only DRCV is output
  sta data	; idle state of lines is high
  sta ddr
#endif
  cli
  rts

#if ramexp & piaexp
piatable:
  .byte $34,$fe,4,$ff,0,$ff,0,$dc,4,$fe,4
#endif

irq:
#if (target & c64) && pa2_used
  lda #ackval	; this is needed for Action Replay, whose fastload command
  ora ack	; resets the PA2 line
  sta ack
#endif
#if cable & (prlink | prlink88)
  lda #strval
  bit strobe	; check the -FLAG signal
  beq return	; jump if the client didn't want to send anything
  ldx #0
  stx ddr	; restore the data lines to inputs
#endif
#if cable & pc64
  lda #strval
  bit strobe	; check the -FLAG signal
  beq return	; jump if the client didn't want to send anything
  ldx #$f
  stx ddr	; restore the data lines to inputs/outputs
#endif

#if cable & c64net
  lda data
  and #$F8	; check if the remote host wants to send a byte
  eor #8
  bne return	; jump if not

  lda #$7
  sta data
  sta ddr
#endif

#if cable & transnib
  bit data	; test if DRDY is low.
  bmi return
  lda #$40	; prepare for input: only DRCV is output
  sta data	; idle state of lines is high
  sta ddr
#endif

  jsr rereceive ; receive byte without requiring handshaking
  cmp #cmdinfo
  bne load	; branch if the client did not request for host info
  lda #host	; return the host info byte
  jsr send_switch
  lda #<mystart ; tell the driver start address
  jsr send
  lda #>mystart
  jsr send
  lda bstart	; and the BASIC start address
  jsr send
  lda bstart+1
  jsr send

return:
oldirq = * + 1
  jmp * 	; continue the normal irq (selfmodifying code)

load:
  cmp #cmdload	; was it the command for loading?
  beq 0$
  jmp jump	; no, skip

0$:
  jsr gethdr	; get the addresses
#if bank
  lda bank	; other bank than the default specified => can't be basic
  bne 1$
#endif
  lda start	; check if it is a basic program
  eor bstart
  bne 1$
  lda start+1
  eor bstart+1
1$:
  pha		; accu is 0 if it is a basic program
#if target & (c64 | c128)
  lda $d011
  pha
  lda $d030
  pha
  lda #$1
  sta $d011	; blank the screen
  sta $d030	; switch to 2 MHz mode
#endif

#if ramexp & reuexp
  lda bank
  cmp #reubmin	; is it a REU bank?
  bcc noreu$	; no, do not save REC registers on stack

#if actionreuplay
  lda #$2a
  sta $de00	; enable Action Replay RAM at $df00 (disable the ROM)
		; Action Replay has one write-only I/O register at $de00-$deff.
		; Its bits are as follows:
		; 7 - not used
		; 6 - probably resets the IRQ/NMI flipflop in the freezer mode
		; 5 - enables RAM at I/O2
		; 4 - bank selector
		; 3 - bank selector
		; 2 - 1=cartridge off
		; 1 - 1=-EXROM high
		; 0 - 1=-GAME low
#else
  ldx #10
11$:
  lda reu,x
  pha
  dex
  bne 11$
#endif
  lda end+1	; store the end of file pointer high byte
  pha
  jsr reuinit	; initialize the REU registers.  C flag is set at this stage.
12$:
  jsr receive
  sta (start),y
  jsr incmptreu
  bne 12$

  dec $d030	; switch to 1 MHz mode
  lda #$f2
  sta reu+1	; swap the REU memory back
  pla
  sta start+1	; adjust the end address pointers
  sta end+1

#if actionreuplay
  lda #$0a
  sta $de00	; restore normal Action Replay configuration
#else		; actionreuplay
  ldx #0
13$:
  inx
  pla
  sta reu,x
  cpx #10
  bne 13$
#endif		; actionreuplay
  jmp endload

noreu$:
#endif		; ramexp & reuexp

#if ramexp & piaexp
  lda end+1	; store the end of file pointer high byte
  pha
  lda pia	; store the PIA memory configuration
  pha
#if target & c128
  lda $d506	; store the common memory configuration
  pha
#endif
  jsr piainit	; initialize the PIA expansion (with $d506 value in A)
2$:
  jsr receive
  sta (start),y
  jsr incmptr
  bne 2$

#if target & c128
  pla		; restore the original MMU banking
  ldx #0	; enable all ROMs, select RAM bank 0
  stx $d500
  sta $d506	; restore the common memory configuration
#endif
  pla
  sta pia
  pla
  sta start+1	; adjust the end address pointers
  sta end+1
#else		; ramexp & piaexp
#if target & c128
  lda pokeptr
  pha
  lda #start
  sta pokeptr

2$:
  jsr receive	; get the bytes
  ldx bank
  jsr poke
  jsr incmptr	; update the pointer
  bne 2$

  sty bank
  pla
  sta pokeptr
#else		; target & c128
2$:
  jsr receive	; get the bytes
  sta (start),y
  jsr incmptr	; update the pointer
  bne 2$
#endif		; target & c128
#endif		; ramexp & piaexp

endload:
#if target & (c64 | c128)
  pla
  sta $d030	; restore original speed
  pla
  sta $d011	; and screen mode
#endif

  pla
  bne 0$	; it was not a basic program
  lda end	; set the basic end address
  sta bend
  lda end+1
  sta bend+1
  jsr linkprg	; relink the program
#if target & c128
  lda #0
  sta $ff00	; restore the MMU configuration (linkprg changes it)
#endif
0$:
  jmp (oldirq)

jump:
  cmp #cmdjump	; was it the command for jumping?
  bne save	; no, skip

  jsr receive	; get the memory configuration (for the c128)
#if target & c128
  sta bank	; and temporarily store it
#endif
  jsr receive	; get the jump address low
  tax
  jsr receive	; get the jump address high
  pha		; and store it
  txa
  pha		; store the jump address low
  lda #0
  pha		; clear the flags
  pha		; and the registers
  pha
  pha
#if target & c128
  lda bank
  pha		; store the MMU configuration
#endif
  jsr deinstall ; deinstall the IRQ routine
#if target & c128
#else
  sta crsw	; turn the cursor off
  sta blnsw
#endif
  jmp (oldirq)

save:
  cmp #cmdsave
  bne run

#if target & (c64 | c128)
  lda $d011
  pha
  lda $d030
  pha
  lda #$1
  sta $d011	; blank the screen
  sta $d030	; switch to 2 MHz mode
#endif

  jsr gethdr	; get the pointers

#if ramexp & reuexp
  lda bank
  cmp #reubmin	; is it a REU bank?
  bcc noreu$	; no, jump to normal save

#if actionreuplay
  lda #$2a
  sta $de00	; disable Action ROM at $df00
#else
  ldx #10
11$:
  lda reu,x	; store the REU registers
  pha
  dex
  bne 11$
#endif
  lda end+1	; store the end of file pointer high byte
  pha
  jsr reuinit	; initialize the REU registers.  C flag is set at this stage.
#if send != send_switch
  lda (start),y	; unrolled once
  jsr send_switch
  jsr incmptreu
  beq skiploop$
#endif		; send != send_switch
loop$:
  lda (start),y
  jsr send
  jsr incmptreu
  bne loop$
skiploop$:

  dec $d030	; switch to 1 MHz mode
  lda #$f2
  sta reu+1	; swap the REU memory back
  pla
  sta start+1
  sta end+1

#if actionreuplay
  lda #$0a
  sta $de00	; restore normal Action Replay configuration
#else		; actionreuplay
  ldx #0
13$:
  inx
  pla
  sta reu,x
  cpx #10
  bne 13$
#endif		; actionreuplay
  jmp endsave

noreu$:
#endif		; ramexp & reuexp

#if ramexp & piaexp
  lda pia	; store the PIA memory configuration
  pha
#if target & c128
  lda $d506	; store the common memory configuration
  pha
#endif
  jsr piainit	; initialize the PIA expansion (with $d506 value in A)
#if send != send_switch
  lda (start),y	; unrolled once
  jsr send_switch
  jsr incmptr
  beq skiploop$
#endif		; send != send_switch
loop$:
  lda (start),y
  jsr send
  jsr incmptr
  bne loop$
skiploop$:

#if target & c128
  pla
  ldx #0
  stx $d500
  sta $d506
#endif
  pla
  sta pia
#else		; ramexp & piaexp
#if target & c128
  lda peekptr
  pha
  lda #start
  sta peekptr

#if send != send_switch
  ldx bank	; unrolled once
  jsr peek
  jsr send_switch
  jsr incmptr
  beq skiploop$
#endif		; send != send_switch

loop$:
  ldx bank
  jsr peek
  jsr send
  jsr incmptr
  bne loop$
skiploop$:

  sty bank
  pla
  sta peekptr
#else		; target & c128
#if target & c64
#if send != send_switch
  ldx 1		; unrolled once
  lda #$34
  sta 1 	; switch to 64 kB RAM config
  lda (start),y
  stx 1 	; restore the normal config
  jsr send_switch
  jsr incmptr
  beq skiploop$
#endif		; send != send_switch

  ldx 1
loop$:
  lda #$34
  sta 1 	; switch to 64 kB RAM config
  lda (start),y
  stx 1 	; restore the normal config
#else		; target & c64
#if send != send_switch
  lda (start),y	; unrolled once
  jsr send_switch
  jsr incmptr
  beq skiploop$
#endif		; send != send_switch
loop$:
  lda (start),y
#endif		; target & c64
  jsr send
  jsr incmptr
  bne loop$
skiploop$:
#endif		; target & c128
#endif		; ramexp & piaexp

endsave:
#if target & (c64 | c128)
  pla
  sta $d030	; restore original speed
  pla
  sta $d011	; and screen mode
#endif		; target & (c64 | c128)

return2:
  jmp (oldirq)	; return from interrupt

run:
  cmp #cmdrun
  bne return2

  jsr deinstall ; Install the original interrupt routine
#if target & c128
  cli		; process the pending interrupt in a very kludgeous manner.
  jmp basrun
#else
  sta crsw	; turn the cursor off
  sta blnsw
  cli		; process the pending interrupt in a very kludgeous manner.
  jsr clr	; The stack won't run out, since the BASIC clr call
		; initializes the stack pointer.
  jsr stxpt	; Set the BASIC text pointer (to the beginning of the prg)
  jmp newstt	; BASIC warm start
#endif

deinstall:	; restore the original interrupt routine
  lda oldirq
  sta cinv
  lda oldirq+1
  sta cinv+1
  rts

gethdr:
  jsr receive	; get the memory bank byte
#if ramexp
  sta bank
#else
#if target & c128
  lsr
  ror
  ror
  ora #$3f
  sta bank
#endif		; target & c128
#endif		; ramexp
  lda #0	; send the acknowledgement code 0
  jsr send_switch
  jsr receive_switch ; get the file start and end vectors
  sta start
  jsr receive
  sta start+1
  jsr receive
  sta end
  jsr receive
  sta end+1
  rts

#if ramexp & piaexp
incmptr:	; increment and compare the current byte pointer
  inc start	; and change the PIA bank if necessary.
  bne 0$
  inc start+1
  bpl 0$
  dex		; decrease the bank jump counter
  lda #$40
  sta start+1	; restore the address
  clc
  lda #$10
  adc pia
  sta pia	; and adjust the PIA bank
0$:
  txa		; is it the last bank?
  bne 1$	; no, return
  lda start	; perform the comparison
  cmp end
  bne 1$
  lda start+1
  cmp end+1
1$:
  rts
#else		; ramexp & piaexp
incmptr:	; increment and compare the current byte pointer.
  inc start	; increment.
  bne 0$
  inc start+1
0$:
  lda start	; compare.  if start == end, the zero flag will be set.
  cmp end
  bne 1$
  lda start+1
  cmp end+1
1$:
  rts
#endif		; ramexp & piaexp

#if ramexp & reuexp
incmptreu:
  inc start	; increment and compare the current byte pointer
  bne 0$	; and transfer another REU block in if necessary.
  inc start+1
  bpl 0$
  dex		; decrease the bank jump counter
  dec $d030	; slow down to 1 MHz
  lda #$f2
  sta reu+1	; swap the buffers
  lda #$40
  sta start+1	; restore the REU buffer address
  clc
#if actionreuplay
  adc bank
  sta bank
#else
  adc reu+5
#endif
  sta reu+5	; update the REU memory pointer
  lda #$f2
  sta reu+1	; swap the buffers
  inc $d030	; switch back to 2 MHz mode
0$:
  txa		; is it the last bank?
  bne 1$	; no, return
  lda start	; perform the comparison
  cmp end
  bne 1$
  lda start+1
  cmp end+1
1$:
  rts
#endif		; ramexp & reuexp

#if cable & (prlink | prlink88)

  ; .A := data, .Y := 00, .X preserved
receive_switch:
		;;; wait for first part of handshake
  lda #strval
1$:
  bit strobe	; wait for handshaking
  beq 1$
#if clearviaifr
  sta strobe
#endif		; clearviaifr

		;;; and only then switch data direction.
  lda #0	; switch back to inputs
  sta ddr

  beq receive1	; branch always

receive:
#if clearviaifr
rereceive:	; rereceive (without handshake) is only different for the CIA
#endif
  lda #strval
0$:
  bit strobe	; wait for handshaking
  beq 0$
#if clearviaifr
  sta strobe
#else
rereceive:	; rereceive (receive without handshaking) for the CIA
#endif		; clearviaifr
receive1:
  lda #ackval
  eor ack
  ldy data	; read the byte
  sta ack	; acknowledge
  tya
  ldy #0
  rts

  ; .A trashed, .Y := 00, .X preserved
send_switch:
		;;; wait for first part of handshake
  tay
  lda #strval
1$:
  bit strobe	; wait for handshaking
  beq 1$
#if clearviaifr
  sta strobe
#endif
		;;; and only then switch data direction.
#if cable & prlink88
  lda #$ff
#else
  lda #$0f
#endif
  sta ddr	; set the data lines to output
  bne send1	; branch always

send:
  tay
  lda #strval
0$:
  bit strobe	; wait for handshaking
  beq 0$
#if clearviaifr
  sta strobe
#endif
send1:
#if cable & prlink88
#else
  tya
  sta data	; send the low nybble
  lsr
  lsr
  lsr
  lsr
  tay		; move the high nybble to y
  lda #ackval
  eor ack
  sta ack	; ack: the low nybble is on the bus
  lda #strval
1$:
  bit strobe	; handshake
  beq 1$
#if clearviaifr
  sta strobe
#endif		; via
#endif		; prlink88
  sty data	; send the high nybble (or the whole byte, for prlink88)
  ldy #0
  lda ack
  eor #ackval
  sta ack	; ack: the high nybble is on the bus
  rts

#endif		; prlink | prlink88

#if cable & pc64

  ; .A := data, .Y := 00, .X preserved
receive_switch:
receive:
#if clearviaifr
rereceive:
#endif
  lda #strval
0$:
  bit strobe	; wait for handshaking
  beq 0$
#if clearviaifr
  sta strobe
#else
rereceive:
#endif
  lda ack
  and #255 - ackval
  ldy data
  sta ack
  tya
  lsr
  lsr
  lsr
  lsr
  sta stemp
  lda #strval
1$:
  bit strobe
  beq 1$
#if clearviaifr
  sta strobe
#endif
  lda ack
  ora #ackval
  tay
  lda data
  sty ack
  and #$F0
  ora stemp
  ldy #0
  rts

  ; .A trashed, .Y := 00, .X preserved
send_switch:
send:
  tay
  lda #strval
0$:
  bit strobe	; wait for handshaking
  beq 0$
#if clearviaifr
  sta strobe
#endif
  sty data
  lda ack
  and #255 - ackval
  sta ack
  tya
  lsr
  lsr
  lsr
  lsr
  tay
  lda #strval
1$:
  bit strobe	; wait for handshaking
  beq 1$
#if clearviaifr
  sta strobe
#endif
  sty data
  lda ack
  ora #ackval
  sta ack
  ldy #0
  rts

#endif		; pc64

#if cable & c64net

  ; .A := data, .Y := 00, .X preserved
receive_switch:
receive:
rereceive:
  lda #8
0$:
  bit data	; initial handshaking
  beq 0$
  lda data	; get the high nybble
  and #$f0
  sta stemp
  lda #8
  sta data	; acknowledge (place 0 on PB2)
1$:
  bit data	; wait for acknowledgement
  bne 1$
  ldy #4
  lda data	; get the low nybble
  sty data	; acknowledge
  ldy #0
  lsr
  lsr
  lsr
  lsr
  ora stemp
  rts

  ; .A trashed, .Y := 00, .X preserved
send_switch:	; switch to sending and send
send:
  tay
0$:
  lda data	; initial handshaking
  and #$f8
  eor #$f0
  bne 0$
  lda #0
  sta data
1$:
  lda data
  bne 1$
  tya
  ora #4
  sta data	; send the lowest bit pair
  lda #8
2$:
  bit data	; wait for acknowledgement
  beq 2$
  tya
  lsr
  lsr
  tay
  and #3
  sta data	; send the lowest bit pair but one
  lda #8
3$:
  bit data	; wait for acknowledgement
  bne 3$
  tya
  lsr
  lsr
  tay
  ora #4
  sta data	; send the highest bit pair but one
  lda #8
4$:
  bit data	; wait for acknowledgement
  beq 4$
  tya
  lsr
  lsr
  sta data	; send the highest bit pair
  lda #8
5$:
  bit data	; wait for acknowledgement
  bne 5$
  lda #4
  sta data
  ldy #0
  rts

#endif		; pc64

#if cable & transnib

  ; .A := data, .Y := 00, .X preserved
receive_switch:
  lda #$40	; $40 is DRCV (output), $80 is DRDY (input)
  sta ddr
receive:
rereceive:
  jsr recvnyb	; high nybble first
  asl
  asl
  asl
  asl
  sta stemp
  jsr recvnyb
  ldy #0	; (y is preserved in this function)
  ora stemp
  rts

recvnyb:
rdrdyhi:
  bit data	; - Receiver starts waiting for DRDY to go low.
  bmi rdrdyhi
		; - Sender puts nybble on data lines, pulls DRDY low and waits
		; for DRCV to go low.
  lda data	; - Receiver gets nybble,
  and #$ff-$40	;   pulls DRCV low
  sta data
rdrdylo:
  bit data	;   and waits for DRDY to go high.
  bpl rdrdylo
		; - Sender pulls DRDY high and waits for DRCV to go high.
  ora #$40
  sta data	; - Receiver pulls DRCV high
  and #$0f
  rts

  ; .A trashed, .Y := 00, .X preserved
send_switch:
  ldy #$4f	; $80 is DRCV (input), $40 is DRDY (output)
  sty ddr	; note that the names are swapped from receiving but the
		; data direction isn't!
send:
  tay		; high nybble first
  lsr
  lsr
  lsr
  lsr
  jsr sendnyb
  tya
  and #$0f	; fall through to send low nybble
  ldy #0	; clear y

sendnyb:	; - Receiver starts waiting for DRDY to go low.
  sta data	; - Sender puts nybble on data lines, pulls DRDY low and
rdrcvhi:
  bit data	;   waits or DRCV to go low.
  bmi rdrcvhi
		; - Receiver gets nybble, pulls DRCV low
		;   and waits for DRDY to go high.
  ora #$40	; - Sender pulls DRDY high and
  sta data
rdrcvlo:
  bit data	;   waits for DRCV to go high.
  bpl rdrcvlo

  rts

#endif

#if ramexp & piaexp
piainit:
#if target & c128
  ora #$3f	; the accu must be loaded with $d506 when calling this routine
  sta $d506	; set the MMU configuration to 32kB common memory (top and low)
  lda bank
  and #$f
  lsr
  ror
  ror
  tax
  and #$c0
  ora #2
  sta $d500	; set the MMU banking (disabling the BASIC ROM)
  txa
  ror
  ror
#else
  lda bank
  asl
  asl
  asl
  asl
#endif
  eor #$c0
  and #$c0
  ora #$c
  sta pia	; store the PIA banking configuration
  lda start+1
  lsr
  lsr
  and #$30
  ora pia
  sta pia	; set the initial PIA configuration
#endif		; ramexp & piaexp
#if ramexp
rptrinit:
  sec
  lda end+1
  ora #$3f
  sbc start+1	; get the amount of bank crossings
  asl
  rol
  rol
  and #3
  tax		; and store it to x
  bne 0$	; check for address wraparound
  lda start
  cmp end	; if start >= end, the amount of bank crossings will be 4.
  lda start+1
  sbc end+1
  bcc 0$
  ldx #4
0$:
  lda start+1
  and #$3f
  ora #$40
  sta start+1
  lda end+1
  and #$3f
  ora #$40
  sta end+1
  rts
#endif		; ramexp

#if ramexp & reuexp
reuinit:
  lda #0
  ldx #$40
  sta reu+2	; set the buffer address for the C64/C128
  stx reu+3
  sta reu+7	; set the buffer length
  stx reu+8
  sta reu+9	; reset some other registers
  sta reu+10
  lda bank
  sbc #reubmin	; set the memory bank (C flag initially set)
  sta reu+6
  lda start	; set the start address in the REU
  sta reu+4
  lda start+1
  sta reu+5
#if actionreuplay
  sta bank
#endif
#if target & c128
  lda #2
  sta $ff00	; switch to RAM bank 0 and disable the BASIC ROM
#endif
  dec $d030	; slow down to 1 MHz
  lda #$f2
  sta reu+1	; swap the buffers
  inc $d030	; speed up again
  jmp rptrinit
#endif		; ramexp & reuexp
