summaryrefslogtreecommitdiff
path: root/src/engine/link/ir_core.asm
diff options
context:
space:
mode:
authorElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-27 11:56:10 +0100
committerElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-27 11:56:10 +0100
commit7825b5ef0f09a877142ea1eb221e895bb60a0253 (patch)
tree9d46dfebd219919f5144786caf3ebfdf7cdab3a7 /src/engine/link/ir_core.asm
parent48f83527c769441b6c123f3382d90e2e962ef9a0 (diff)
Split bank 6
Diffstat (limited to 'src/engine/link/ir_core.asm')
-rw-r--r--src/engine/link/ir_core.asm531
1 files changed, 531 insertions, 0 deletions
diff --git a/src/engine/link/ir_core.asm b/src/engine/link/ir_core.asm
new file mode 100644
index 0000000..ab9eaae
--- /dev/null
+++ b/src/engine/link/ir_core.asm
@@ -0,0 +1,531 @@
+; if carry flag is set, only delays
+; if carry not set:
+; - set rRP to $c1, wait;
+; - set rRP to $c0, wait;
+; - return
+Func_19674:
+ jr c, .delay_once
+ ld [hl], $c1
+ ld a, 5
+ jr .loop_delay_1 ; jump to possibly to add more cycles?
+.loop_delay_1
+ dec a
+ jr nz, .loop_delay_1
+ ld [hl], $c0
+ ld a, 14
+ jr .loop_delay_2 ; jump to possibly to add more cycles?
+.loop_delay_2
+ dec a
+ jr nz, .loop_delay_2
+ ret
+
+.delay_once
+ ld a, 21
+ jr .loop_delay_3 ; jump to possibly to add more cycles?
+.loop_delay_3
+ dec a
+ jr nz, .loop_delay_3
+ nop
+ ret
+
+; input a = byte to transmit through IR
+TransmitByteThroughIR:
+ push hl
+ ld hl, rRP
+ push de
+ push bc
+ ld b, a
+ scf ; carry set
+ call Func_19674
+ or a ; carry not set
+ call Func_19674
+ ld c, 8
+ ld c, 8 ; number of input bits
+.loop
+ ld a, $00
+ rr b
+ call Func_19674
+ dec c
+ jr nz, .loop
+ pop bc
+ pop de
+ pop hl
+ ldh a, [rJOYP]
+ bit 1, a ; P11
+ jr z, ReturnZFlagUnsetAndCarryFlagSet
+ xor a ; return z set
+ ret
+
+; same as ReceiveByteThroughIR but
+; returns $0 in a if there's an error in IR
+ReceiveByteThroughIR_ZeroIfUnsuccessful:
+ call ReceiveByteThroughIR
+ ret nc
+ xor a
+ ret
+
+; returns carry if there's some time out
+; and output in register a of $ff
+; otherwise returns in a some sequence of bits
+; related to how rRP sets/unsets bit 1
+ReceiveByteThroughIR:
+ push de
+ push bc
+ push hl
+
+; waits for bit 1 in rRP to be unset
+; up to $100 loops
+ ld b, 0
+ ld hl, rRP
+.wait_ir
+ bit 1, [hl]
+ jr z, .ok
+ dec b
+ jr nz, .wait_ir
+ ; looped around $100 times
+ ; return $ff and carry set
+ pop hl
+ pop bc
+ pop de
+ scf
+ ld a, $ff
+ ret
+
+.ok
+; delay for some cycles
+ ld a, 15
+.loop_delay
+ dec a
+ jr nz, .loop_delay
+
+; loop for each bit
+ ld e, 8
+.loop
+ ld a, $01
+ ; possibly delay cycles?
+ ld b, 9
+ ld b, 9
+ ld b, 9
+ ld b, 9
+
+; checks for bit 1 in rRP
+; if in any of the checks it is unset,
+; then a is set to 0
+; this is done a total of 9 times
+ bit 1, [hl]
+ jr nz, .asm_196ec
+ xor a
+.asm_196ec
+ bit 1, [hl]
+ jr nz, .asm_196f1
+ xor a
+.asm_196f1
+ dec b
+ jr nz, .asm_196ec
+ ; one bit received
+ rrca
+ rr d
+ dec e
+ jr nz, .loop
+ ld a, d ; has bits set for each "cycle" that bit 1 was not unset
+ pop hl
+ pop bc
+ pop de
+ or a
+ ret
+
+ReturnZFlagUnsetAndCarryFlagSet:
+ ld a, $ff
+ or a ; z not set
+ scf ; carry set
+ ret
+
+; called when expecting to transmit data
+Func_19705:
+ ld hl, rRP
+.asm_19708
+ ldh a, [rJOYP]
+ bit 1, a
+ jr z, ReturnZFlagUnsetAndCarryFlagSet
+ ld a, $aa ; request
+ call TransmitByteThroughIR
+ push hl
+ pop hl
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $33 ; acknowledge
+ jr nz, .asm_19708
+ xor a
+ ret
+
+; called when expecting to receive data
+Func_1971e:
+ ld hl, rRP
+.asm_19721
+ ldh a, [rJOYP]
+ bit 1, a
+ jr z, ReturnZFlagUnsetAndCarryFlagSet
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $aa ; request
+ jr nz, .asm_19721
+ ld a, $33 ; acknowledge
+ call TransmitByteThroughIR
+ xor a
+ ret
+
+ReturnZFlagUnsetAndCarryFlagSet2:
+ jp ReturnZFlagUnsetAndCarryFlagSet
+
+TransmitIRDataBuffer:
+ call Func_19705
+ jr c, ReturnZFlagUnsetAndCarryFlagSet2
+ ld a, $49
+ call TransmitByteThroughIR
+ ld a, $52
+ call TransmitByteThroughIR
+ ld hl, wIRDataBuffer
+ ld c, 8
+ jr TransmitNBytesFromHLThroughIR
+
+ReceiveIRDataBuffer:
+ call Func_1971e
+ jr c, ReturnZFlagUnsetAndCarryFlagSet2
+ call ReceiveByteThroughIR
+ cp $49
+ jr nz, ReceiveIRDataBuffer
+ call ReceiveByteThroughIR
+ cp $52
+ jr nz, ReceiveIRDataBuffer
+ ld hl, wIRDataBuffer
+ ld c, 8
+ jr ReceiveNBytesToHLThroughIR
+
+; hl = start of data to transmit
+; c = number of bytes to transmit
+TransmitNBytesFromHLThroughIR:
+ ld b, $0
+.loop_data_bytes
+ ld a, b
+ add [hl]
+ ld b, a
+ ld a, [hli]
+ call TransmitByteThroughIR
+ jr c, .asm_1977c
+ dec c
+ jr nz, .loop_data_bytes
+ ld a, b
+ cpl
+ inc a
+ call TransmitByteThroughIR
+.asm_1977c
+ ret
+
+; hl = address to write received data
+; c = number of bytes to be received
+ReceiveNBytesToHLThroughIR:
+ ld b, 0
+.loop_data_bytes
+ call ReceiveByteThroughIR
+ jr c, ReturnZFlagUnsetAndCarryFlagSet2
+ ld [hli], a
+ add b
+ ld b, a
+ dec c
+ jr nz, .loop_data_bytes
+ call ReceiveByteThroughIR
+ add b
+ or a
+ jr nz, ReturnZFlagUnsetAndCarryFlagSet2
+ ret
+
+; disables interrupts, and sets joypad and IR communication port
+; switches to CGB normal speed
+StartIRCommunications:
+ di
+ call SwitchToCGBNormalSpeed
+ ld a, P14
+ ldh [rJOYP], a
+ ld a, $c0
+ ldh [rRP], a
+ ret
+
+; reenables interrupts, and switches CGB back to double speed
+CloseIRCommunications:
+ ld a, P14 | P15
+ ldh [rJOYP], a
+.wait_vblank_on
+ ldh a, [rSTAT]
+ and STAT_LCDC_STATUS
+ cp STAT_ON_VBLANK
+ jr z, .wait_vblank_on
+.wait_vblank_off
+ ldh a, [rSTAT]
+ and STAT_LCDC_STATUS
+ cp STAT_ON_VBLANK
+ jr nz, .wait_vblank_off
+ call SwitchToCGBDoubleSpeed
+ ei
+ ret
+
+; set rRP to 0
+ClearRP:
+ ld a, $00
+ ldh [rRP], a
+ ret
+
+; expects to receive a command (IRCMD_* constant)
+; in wIRDataBuffer + 1, then calls the subroutine
+; corresponding to that command
+ExecuteReceivedIRCommands:
+ call StartIRCommunications
+.loop_commands
+ call ReceiveIRDataBuffer
+ jr c, .error
+ jr nz, .loop_commands
+ ld hl, wIRDataBuffer + 1
+ ld a, [hl]
+ ld hl, .CmdPointerTable
+ cp NUM_IR_COMMANDS
+ jr nc, .loop_commands ; invalid command
+ call .JumpToCmdPointer ; execute command
+ jr .loop_commands
+.error
+ call CloseIRCommunications
+ xor a
+ scf
+ ret
+
+.JumpToCmdPointer
+ add a ; *2
+ add l
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.jp_hl
+ jp hl
+
+.CmdPointerTable
+ dw .Close ; IRCMD_CLOSE
+ dw .ReturnWithoutClosing ; IRCMD_RETURN_WO_CLOSING
+ dw .TransmitData ; IRCMD_TRANSMIT_DATA
+ dw .ReceiveData ; IRCMD_RECEIVE_DATA
+ dw .CallFunction ; IRCMD_CALL_FUNCTION
+
+; closes the IR communications
+; pops hl so that the sp points
+; to the return address of ExecuteReceivedIRCommands
+.Close
+ pop hl
+ call CloseIRCommunications
+ or a
+ ret
+
+; returns without closing the IR communications
+; will continue the command loop
+.ReturnWithoutClosing
+ or a
+ ret
+
+; receives an address and number of bytes
+; and transmits starting at that address
+.TransmitData
+ call Func_19705
+ ret c
+ call LoadRegistersFromIRDataBuffer
+ jp TransmitNBytesFromHLThroughIR
+
+; receives an address and number of bytes
+; and writes the data received to that address
+.ReceiveData
+ call LoadRegistersFromIRDataBuffer
+ ld l, e
+ ld h, d
+ call ReceiveNBytesToHLThroughIR
+ jr c, .asm_19812
+ sub b
+ call TransmitByteThroughIR
+.asm_19812
+ ret
+
+; receives an address to call, then stores
+; the registers in the IR data buffer
+.CallFunction
+ call LoadRegistersFromIRDataBuffer
+ call .jp_hl
+ call StoreRegistersInIRDataBuffer
+ ret
+
+; returns carry set if request sent was not acknowledged
+TrySendIRRequest:
+ call StartIRCommunications
+ ld hl, rRP
+ ld c, 4
+.send_request
+ ld a, $aa ; request
+ push bc
+ call TransmitByteThroughIR
+ push bc
+ pop bc
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ pop bc
+ cp $33 ; acknowledgement
+ jr z, .received_ack
+ dec c
+ jr nz, .send_request
+ scf
+ jr .close
+
+.received_ack
+ xor a
+.close
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+
+; returns carry set if request was not received
+TryReceiveIRRequest:
+ call StartIRCommunications
+ ld hl, rRP
+.wait_request
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $aa ; request
+ jr z, .send_ack
+ ldh a, [rJOYP]
+ cpl
+ and P10 | P11
+ jr z, .wait_request
+ scf
+ jr .close
+
+.send_ack
+ ld a, $33 ; acknowledgement
+ call TransmitByteThroughIR
+ xor a
+.close
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+
+; sends request for other device to close current communication
+RequestCloseIRCommunication:
+ call StartIRCommunications
+ ld a, IRCMD_CLOSE
+ ld [wIRDataBuffer + 1], a
+ call TransmitIRDataBuffer
+; fallthrough
+
+; calls CloseIRCommunications while preserving af
+SafelyCloseIRCommunications:
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+
+; sends a request for data to be transmitted
+; from the other device
+; hl = start of data to request to transmit
+; de = address to write data received
+; c = length of data
+RequestDataTransmissionThroughIR:
+ ld a, IRCMD_TRANSMIT_DATA
+ call TransmitRegistersThroughIR
+ push de
+ push bc
+ call Func_1971e
+ pop bc
+ pop hl
+ jr c, SafelyCloseIRCommunications
+ call ReceiveNBytesToHLThroughIR
+ jr SafelyCloseIRCommunications
+
+; transmits data to be written in the other device
+; hl = start of data to transmit
+; de = address for other device to write data
+; c = length of data
+RequestDataReceivalThroughIR:
+ ld a, IRCMD_RECEIVE_DATA
+ call TransmitRegistersThroughIR
+ call TransmitNBytesFromHLThroughIR
+ jr c, SafelyCloseIRCommunications
+ call ReceiveByteThroughIR
+ jr c, SafelyCloseIRCommunications
+ add b
+ jr nz, .asm_1989e
+ xor a
+ jr SafelyCloseIRCommunications
+.asm_1989e
+ call ReturnZFlagUnsetAndCarryFlagSet
+ jr SafelyCloseIRCommunications
+
+; first stores all the current registers in wIRDataBuffer
+; then transmits it through IR
+TransmitRegistersThroughIR:
+ push hl
+ push de
+ push bc
+ call StoreRegistersInIRDataBuffer
+ call StartIRCommunications
+ call TransmitIRDataBuffer
+ pop bc
+ pop de
+ pop hl
+ ret nc
+ inc sp
+ inc sp
+ jr SafelyCloseIRCommunications
+
+; stores af, hl, de and bc in wIRDataBuffer
+StoreRegistersInIRDataBuffer:
+ push de
+ push hl
+ push af
+ ld hl, wIRDataBuffer
+ pop de
+ ld [hl], e ; <- f
+ inc hl
+ ld [hl], d ; <- a
+ inc hl
+ pop de
+ ld [hl], e ; <- l
+ inc hl
+ ld [hl], d ; <- h
+ inc hl
+ pop de
+ ld [hl], e ; <- e
+ inc hl
+ ld [hl], d ; <- d
+ inc hl
+ ld [hl], c ; <- c
+ inc hl
+ ld [hl], b ; <- b
+ ret
+
+; loads all the registers that were stored
+; from StoreRegistersInIRDataBuffer
+LoadRegistersFromIRDataBuffer:
+ ld hl, wIRDataBuffer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ pop hl
+ pop af
+ ret