;; #LAYOUT# STD *        #TAKE
;; #LAYOUT# *   KERNAL_0 #TAKE
;; #LAYOUT# *   *        #IGNORE

; Receive a byte from the IEC bus.
; Implemented based on https://www.pagetable.com/?p=1135, https://github.com/mist64/cbmbus_doc,
; http://www.zimmers.net/anonftp/pub/cbm/programming/serial-bus.pdf (page 11)
;
; Preserves .X and .Y registers


!ifdef CONFIG_IEC {


!ifdef CONFIG_IEC_JIFFYDOS {

iec_rx_dispatch:

!ifdef CONFIG_MB_M65 {
	; Ensure 1 Mhz mode and disabled badlines
	jsr m65_speed_iec
}

	lda IECPROTO
	cmp #IEC_JIFFY
	+beq jiffydos_rx_byte

	; FALLTROUGH

} ; CONFIG_IEC_JIFFYDOS


iec_rx_byte:

!ifdef CONFIG_MB_M65 { !ifndef CONFIG_IEC_JIFFYDOS {
	; Ensure 1 Mhz mode and disabled badlines
	jsr m65_speed_iec
} }

	; Store .X and .Y on the stack - preserve them
	+phx_trash_a
	+phy_trash_a

	; Timing is critical here - execute on disabled IRQs
	; The best practice would be to do PHP first, but it seems this is not
	; what the original ROM does; furthermore, pushing additional bytes to
	; stack can wreck autostart softwaree loading at $0100
	sei

	; First, we wait for the talker to release the CLK line
	jsr iec_wait_for_clk_release

	; We then release the DATA to signal we are ready
	; We can use this routine, since we were not pulling CLK anyway
	jsr iec_release_clk_data

	; Wait till data line is released (someone else might be holding it)
	jsr iec_wait_for_data_release

	; Check if EOI
	jsr iec_rx_check_eoi

!ifdef CONFIG_IEC_DOLPHINDOS {

	; Check if DolphinDOS was detected
	lda IECPROTO
	cmp #IEC_DOLPHIN
	bne iec_rx_no_dolphindos

	; For DolphinDOS just fetch the byte from parallel port
	lda CIA2_PRB
	pha
	+bra iec_rx_acknowledge

iec_rx_no_dolphindos:

} ; CONFIG_IEC_DOLPHINDOS

	; Latch input bits in on rising edge of CLK, eight times for eight bits.
	ldx #7

	; Get empty byte to load into.
	lda #$00
	pha

iec_rx_bit_loop:

	; Wait for CLK to release
	jsr iec_wait_for_clk_release

	; (we do this implicitly below, with a tighter routine,
	; so that we do not have timing problems, as the requirements
	; are quite tight. Basically we need to read the clock and data
	; bit from the same byte read.

	; DATA now has the next bit, but inverted (well, except that it turns out not to be).
	; DATA is in bit 7, which is a bit annoying.
	; But we can clock it out with a ROL instruction
	; so that it is in C. We can then ROR it into the
	; partial data byte.
	; We use ROR so that we shift in from the top, so that
	; the first bit we shift in ends up in bit 0 after all
	; 8 bits have been read.
	; ODD: For some reason we don't need to invert the
	; received bits.  This is weird, because we invert them
	; on the way out, and everything in the protocol seems
	; to indicate that we sould do so.  But experimentation
	; has confirmed the bits don't need inversion on reception.

	; Move data bit into C flag, and loop until bit 6 clears
	; i.e., the clock has been released.

@1:	
	lda CIA2_PRA
	rol
	bpl @1

	; Pull it into the data byte
	pla
	ror
	pha

	; Wait for CLK to be pulled again, over 300 usec (307 cycles on NTSC)
	; consider this a timeout
	ldy #$19                ; 2 cycles
iec_rx_clk_wait2:
	lda CIA2_PRA            ; 4 cycles
	rol                     ; 2 cycles, to put CLK in as the last bit
	bpl @2                  ; 2 cycles if not jumped
	dey                     ; 2 cycles
    bne iec_rx_clk_wait2    ; 3 cycles if jumped
    
	; Timeout
	jsr kernalstatus_EOI
	pla

	+bra iec_rx_end
@2:
	; More bits?
	dex
	bpl iec_rx_bit_loop

	; FALLTROUGH

iec_rx_acknowledge:

	; Then we must within 1000 usec acknowledge the byte by
	; pulling DATA. At this point, CLK is pulled by the
	; talker and DATA by us, i.e., we are ready to receive
	; the next byte. (p11).
	jsr iec_release_clk_pull_data

	; Retrieve the received byte
	pla
	
	; Restore registers
	sta TBTCNT ; $A4 is a byte buffer according to http://sta.c64.org/cbm64mem.html
	
	; FALLTROUGH

iec_rx_end:

!ifdef CONFIG_MB_M65 {
	; Restore the proper speed
	jsr m65_speed_restore
}

	+ply_trash_a
	+plx_trash_a
	lda TBTCNT

	clc
	cli
	rts
}
