; Use the GET directive to include register definitions as if typed here
        GET     h.RegNames

        AREA    |C$$Code|, CODE, READONLY


        EXPORT  compare_screens
        EXPORT  press_release_key
        EXPORT  socket_eventv
        EXPORT  insert_bytes


XOS_CallAVector        * &20034
XOS_AddCallBack        * &20054
XOS_Byte               * &20006


press_release_key ROUT
;on entry     r0  =  key no
;             r1  =  0 (release) or <>0 (press)
        STMFD     r13!, {r9,r14}
        CMP       r1, #0
        MOV       r1, r0
        MOVEQ     r0, #1        ; release
        MOVNE     r0, #2        ; press
        MOV       r9, #&13      ; keyV
        SWI       XOS_CallAVector
        LDMFD     r13!, {r9,pc}



compare_screens  ROUT
;compare two screenlines and find the first and last changed bytes
;on entry       r0 -> x0 on exit
;               r1 -> x1 on exit
;               r2 -> current screenline
;               r3 -> screenline in previous frame (updated on exit)
;             sp+0 =  length to compare
;on exit        x0 == -1 if no diff
          STMFD     r13!, {r0-r1,r4-r11,r14}
          MVN       r0, #0
          MVN       r1, #0
          LDR       r4, [r13, #4*(11+0)]  ; bytes per line
          MOV       r5, r4
loop
          CMP       r5, #16
          BLT       remainder
          LDMIA     r2!,{r6-r9}
          LDMIA     r3!,{r10-r12,r14}
          CMP       r6,r10
          CMPEQ     r7,r11
          CMPEQ     r8,r12
          CMPEQ     r9,r14
          BNE       not_eq
          SUBS      r5, r5, #16
          BGT       loop
done
          LDMIA     r13!, {r2-r3}
          STR       r0,[r2]
          STR       r1,[r3]
          LDMFD     r13!, {r4-r11,pc}

not_eq
          STMDB     r3,{r6-r9}          ; store it
          CMP       r0, #0              ; r0 < 0 -> first not found yet
          BLT       first_found
not_eq_2
          SUB       r1, r4, r5
          ADD       r1, r1, #16

          CMP       r9, r14             ; Work out the last word within the quad which differs
          SUBEQ     r1, r1, #4
          CMPEQ     r8, r12
          SUBEQ     r1, r1, #4
          CMPEQ     r7, r11
          SUBEQ     r1, r1, #4

          SUBS      r5, r5, #16
          BGT       loop
          B         done

first_found
          SUB       r0, r4, r5

          CMP       r6, r10             ; Work out the first word within the quad which differs
          ADDEQ     r0, r0, #4
          CMPEQ     r7, r11
          ADDEQ     r0, r0, #4
          CMPEQ     r8, r12
          ADDEQ     r0, r0, #4
          B         not_eq_2

remainder_words
          LDR       r6,[r2],#4
          LDR       r10,[r3],#4
          CMP       r6,r10
          BEQ       remainder_words_continue
          STR       r6,[r3,#-4]
          CMP       r0, #0              ; r0 < 0 -> first not found yet
          SUB       r1, r4, r5
          SUBLT     r0, r4, r5
          ADD       r1, r1, #4
remainder_words_continue
          SUBS      r5,r5,#4
          BEQ       done
remainder                               ; Arrive here to process non-quadword remainder
          CMP       r5,#4
          BHS       remainder_words
remainder_bytes
          SUBS      r5,r5,#1
          BLT       done
          LDRB      r6,[r2],#1
          LDRB      r10,[r3],#1
          CMP       r6,r10
          BEQ       remainder_bytes
          CMP       r0, #0              ; r0 < 0 -> first not found yet
          STRB      r6,[r3,#-1]
          SUBLT     r0, r4, r5
          SUB       r1, r4, r5
          SUBLT     r0, r0, #1
          B         remainder_bytes

; Called from EventV
; Implemented in assembler so we can pass on other events as quickly as possible!
; r12 is a pointer to the socket_event_status struct:
;  word 0 = module private word
;  word 1 = callback function pointer
;  word 2 = socket number
;  word 3 = busy flag
socket_eventv       ROUT
        TEQ         r0, #19 ; Internet event
        TEQEQ       r1, #1 ; Socket data/general event
        MOVNE       pc, lr
        STMFD       r13!, {r0-r3,r14}
        LDR         r3, [r12, #8]
        LDR         r14, [r12, #12]
        TEQ         r3, r2 ; Our socket?
        TEQEQ       r14, #0 ; Not busy?
        LDMNEFD     r13!, {r0-r3,pc}
        MRS         r2, CPSR
        ORR         r3, r2, #128 ; IRQs off
        MSR         CPSR_c, r3
        LDR         r3, [r12, #12] ; Double-check callback flag (don't trust EventV to not be re-entered)
        CMP         r3, #0
        BNE         %FT50
        ADR         r0, socket_event_callback_veneer
        MOV         r1, r12
        SWI         XOS_AddCallBack
        MOVVC       r0, #1
        STRVC       r0, [r12, #12] ; Flag as callback registered
50
        MSR         CPSR_cf, r2 ; Restore interrupts + flags (clear V)
        LDMFD       r13!, {r0-r3,r14,pc} ; Claim vector (our socket, so nobody else should be interested in this event)

; Call the callback with r0 -> socket_event_status_t
socket_event_callback_veneer
        STMFD       r13!, {r0, r14}
        MOV         r0, r12
        MOV         lr, pc
        LDMIA       r12, {r12, pc}
        LDMFD       r13!, {r0, pc}

; void insert_bytes(const char *buf, int len)
; Insert bytes into the keyboard buffer
insert_bytes        ROUT
        STMFD       r13!, {r0-r1, r9, lr}
        MRS         r12, CPSR
        ORR         r2, r12, #128 ; Disable IRQs
        BIC         r2, r2, #&f0000000
        ORR         r2, r2, #1<<29 ; nzCv to return free space
        MSR         CPSR_cf, r2
        MOV         r1, #0 ; Keyboard buffer
        MOV         r9, #22 ; CnPV
        SWI         XOS_CallAVector
        ORR         r1, r1, r2, LSL #8 ; r1 = free space
        LDMIA       r13!, {r3, r9}
        BVS         %FT90
        CMP         r9, r1
        BHI         %FT90
10
        LDRB        r2, [r3], #1
        MOV         r0, #&99
        MOV         r1, #0
        SWI         XOS_Byte
        SUBS        r9, r9, #1
        BNE         %BT10
90
        MSR         CPSR_c, r12 ; Restore IRQs
        LDMFD       r13!, {r9, pc}

        END
