; ***************************************************************************
; copyright   : (C) 2025 by Martin Preuss
; email       : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome".                              *
; * Please see toplevel file COPYING of that project for license details.   *
; ***************************************************************************

#ifndef AQH_AVR_ILI9341_GRAPHOPS_ASM
#define AQH_AVR_ILI9341_GRAPHOPS_ASM



; ---------------------------------------------------------------------------
; @routine Display_FillRect @global
;
; @param r3:r2 color
; @param r5:r4   X0
; @param r7:r6   Y0
; @param r9:r8   X1/W
; @param r11:r10 Y1/H
; @clobbers R16, R17, R20, R21, R22, R23, R24, R25

Display_FillRect:
#if 1
  push r15
    in r15, SREG
    cli

    rcall ili9341BeginSpi                   ; (R16, R17)
    rcall ili9341SetAddressWindow           ; (R16, r20, r21)
  
    mov r22, r10  ; H low
    mov r23, r11  ; H high
    ldi r16, ILI9341_CMD_RAMWR              ; start writing ro RAM
    rcall ili9341SendCommand                ; (R16)
  
    cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS low
    sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN   ; D high (DATA)
Display_FillRect_loopH:
      mov r24, r8 ; W low
      mov r25, r9 ; W high
Display_FillRect_loopW:
        mov r16, r3
;        rcall SPIHW_MasterTransfer          ; (R16)
        M_SPIHW_MASTER_SEND_BYTE r16        ; (R16)
        mov r16, r2
;        rcall SPIHW_MasterTransfer          ; (R16)
        M_SPIHW_MASTER_SEND_BYTE r16        ; (R16)
        sbiw r25:r24, 1
      brne Display_FillRect_loopW
      mov r24, r22    ; remaining H low
      mov r25, r23    ; remaining H high
      sbiw r25:r24, 1 ; dec
      mov r22, r24    ; save in r23:r22
      mov r23, r25
    brne Display_FillRect_loopH
    sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS high
    rcall ili9341EndSpi
    out SREG, r15
  pop r15
  ret
#else
  push r15
    in r15, SREG
    cli

    rcall ili9341BeginSpi                   ; (R16, R17)
    rcall ili9341SetAddressWindow           ; (R16, r20, r21)

    mov r20, r8
    mov r21, r9
    mov r22, r10
    mov r23, r11
    bigcall Utils_Mulu16x16_32
    mov r24, r16
    mov r25, r17
    rcall displaySendColor

    sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS high
    rcall ili9341EndSpi
    out SREG, r15
  pop r15
  ret
    
#endif
; @end



; ---------------------------------------------------------------------------
; @routine Display_DrawRect @global
;
; @param r3:r2 color
; @param r5:r4   X
; @param r7:r6   Y
; @param r9:r8   W
; @param r11:r10 H

Display_DrawRect:
  push r15
    in r15, SREG
    cli

    ; upper H line
    rcall Display_DrawHLine   ; (R16, R17, R20, R21, R24, R25)

    push r6                    ; save Y0
      push r7
        add r6, r10            ; Y+=(H-1)
        adc r7, r11
        ldi r16, 1
        clr r17
        sub r6, r16
        sbc r7, r17
        ; lower H line
        rcall Display_DrawHLine
      pop r7
    pop r6
    
    ; left V line
    rcall Display_DrawVLine

    push r4                    ; save X0
      push r5
        add r4, r8             ; X+=W-1
        adc r5, r9
        ldi r16, 1
        clr r17
        sub r4, r16
        sbc r5, r17
        ; right V line
        rcall Display_DrawVLine
      pop r5
    pop r4

    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Display_DrawHLine @global
;
; @param r3:r2 color
; @param r5:r4   X
; @param r7:r6   Y
; @param r9:r8   W
; @clobbers R16, R17, R20, R21, R24, R25

Display_DrawHLine:
  push r15
    in r15, SREG
    cli

    push r10
      push r11
        clr r10
        inc r10                        ; height is 1
        clr r11
        rcall ili9341BeginSpi          ; (R16, R17)
        rcall ili9341SetAddressWindow  ; (R16, r20, r21)
      pop r11
    pop r10
    mov r24, r8                        ; W low
    mov r25, r9                        ; W high
    rcall displaySendColor             ; (R16)

    rcall ili9341EndSpi
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Display_DrawVLine @global
;
; @param r3:r2 color
; @param r5:r4   X0
; @param r7:r6   Y0
; @param r11:r10 H
; @clobbers R16, R17, R20, R21, R24, R25

Display_DrawVLine:
  push r15
    in r15, SREG
    cli

    push r8
      push r9
        clr r8
        inc r8                              ; width is 1
        clr r9
        rcall ili9341BeginSpi               ; (R16, R17)
        rcall ili9341SetAddressWindow       ; (R16, r20, r21)
      pop r9
    pop r8
    mov r24, r10                            ; H low
    mov r25, r11                            ; H high
    rcall displaySendColor                  ; (R16)

    rcall ili9341EndSpi
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine displaySendColor

; @param r25:r24 number of pixel to write
; @param r3:r2 color to write
; @clobbers r16

displaySendColor:
  ldi r16, ILI9341_CMD_RAMWR              ; start writing ro RAM
  rcall ili9341SendCommand                ; (R16)
  
  cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS low
  sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN   ; D high (DATA)
displaySendColor_loop:
    mov r16, r3
;    rcall SPIHW_MasterTransfer            ; (R16)
    M_SPIHW_MASTER_SEND_BYTE r16
    mov r16, r2
;    rcall SPIHW_MasterTransfer            ; (R16)
    M_SPIHW_MASTER_SEND_BYTE r16
    sbiw r25:r24, 1
  brne displaySendColor_loop
  sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS high
  ret
; @end




; ---------------------------------------------------------------------------
; @routine Display_DrawChar @global

; @param  R16     character to write
; @param  R1:R0   background color
; @param  R3:R2   foreground color
; @param  R5:R4   X (dest)
; @param  R7:R6   Y (dest)
; @param  Z       pointer to font
; @return R18     width of char written (in pixel)
; @return R19     height of char written (in pixel)
; @clobbers any, !Z

Display_DrawChar:
  push r15
    in r15, SREG
    cli

    push zl
      push zh
        mov r22, r16                          ; save char to R22
        adiw zh:zl, FONT_OFFS_WIDTH
        lpm r8, Z+                            ; char width in pixels
        clr r9                               
        lpm r10, Z                            ; char height in pixels
        clr r11
        sbiw zh:zl, FONT_OFFS_WIDTH+1
        
        rcall ili9341BeginSpi                 ; (r16, r17)
        rcall ili9341SetAddressWindow         ; (R16, R20, R21)
      
        ldi r16, ILI9341_CMD_RAMWR            ; start writing ro RAM
        rcall ili9341SendCommand              ; (R16)

        cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN     ; SS low
        sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN ; D high (DATA)

        mov r16, r22                          ; char to write
        rcall FONT_RenderChar                 ; (any)
      pop zh
    pop zl

    sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN         ; SS high
    rcall ili9341EndSpi                       ; (R16)

    out SREG, r15
  pop r15
  ret
; @end






; ---------------------------------------------------------------------------
; @routine Display_BitBlit @global

; @param  r5:r4   X (dest)
; @param  r7:r6   Y (dest)
; @param  r9:r8   W
; @param  r11:r10 H
; @param  X       source data pointer (RAM)
; @clobbers r16, r22, r23, r24, r25, X (r17, r20, r21)

Display_BitBlit:
  push r15
    in r15, SREG
    cli

    rcall ili9341BeginSpi                   ; (r16, r17)
    rcall ili9341SetAddressWindow           ; (R16, R20, R21)
  
    ldi r16, ILI9341_CMD_RAMWR              ; start writing ro RAM
    rcall ili9341SendCommand

    mov r22, r10                            ; store remaining height
    mov r23, r11
    cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS low
    sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN   ; D high (DATA)
Display_BitBlit_loopH:
      mov r24, r8                           ; r25:r24=width in pixel
      mov r25, r9
Display_BitBlit_loopW:
        ld r18, X+                          ; read color from X
        ld r19, X+
;        mov r16, r19
;        rcall SPIHW_MasterTransfer          ; (R16)
        M_SPIHW_MASTER_SEND_BYTE r19
;        mov r16, r18
;        rcall SPIHW_MasterTransfer          ; (R16)
        M_SPIHW_MASTER_SEND_BYTE r18
        sbiw r25:r24, 1
      brne  Display_BitBlit_loopW
      mov r24, r22
      mov r25, r23
      sbiw r25:r24, 1
      mov r22, r24
      mov r23, r25
    brne Display_BitBlit_loopH
    sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS high
    rcall ili9341EndSpi                     ; (R16)
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341BitBlitStretch2

; @param  r5:r4   X (dest)
; @param  r7:r6   Y (dest)
; @param  r9:r8   W
; @param  r11:r10 H
; @param  X       source data pointer (RAM)
; @clobbers r16, r22, r23, r24, r25, X (r17, r18, r19, r20, r21)

ili9341BitBlitStretch2:
  push r15
    in r15, SREG
    cli

    push r8
      push r9
        push r10
          push r11
            ; width
            lsl r8  ; x2
            rol r9
            ; height
            lsl r10  ; x2
            rol r11
            
            rcall ili9341BeginSpi                       ; (r16, r17)
            rcall ili9341SetAddressWindow               ; (R16, R20, R21)
          pop r11
        pop r10
      pop r9
    pop r8
    ldi r16, ILI9341_CMD_RAMWR                  ; start writing ro RAM
    rcall ili9341SendCommand

    mov r22, r10
    mov r23, r11
    cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN           ; SS low
    sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN       ; D high (DATA)
    ldi r17, 2
ili9341BitBlitStretch2_loopH:
      mov r20, xl                               ; preserve for next run
      mov r21, xh
      rcall ili9341BitBlitStretchNWriteLine     ; (r16, r17, r18, r19, r24, r25, X)
      mov xl, r20
      mov xh, r21
      rcall ili9341BitBlitStretchNWriteLine     ; (r16, r17, r18, r19, r24, r25, X)
      mov r24, r22
      mov r25, r23
      sbiw r25:r24, 1
      mov r22, r24
      mov r23, r25
    brne ili9341BitBlitStretch2_loopH
    sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN           ; SS high
    rcall ili9341EndSpi                         ; (R16)
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341BitBlitStretch4

; @param  r5:r4   X (dest)
; @param  r7:r6   Y (dest)
; @param  r9:r8   W
; @param  r11:r10 H
; @param  X       source data pointer (RAM)
; @clobbers r16, r22, r23, r24, r25, X (r17, r20, r21)

ili9341BitBlitStretch4:
  push r15
    in r15, SREG
    cli

    push r8
      push r9
        push r10
          push r11
            ; width
            lsl r8  ; x2
            rol r9
            lsl r8  ; x4
            rol r9
            ; height
            lsl r10  ; x2
            rol r11
            lsl r10  ; x4
            rol r11
            
            rcall ili9341BeginSpi                       ; (r16, r17)
            rcall ili9341SetAddressWindow               ; (R16, R20, R21)
          pop r11
        pop r10
      pop r9
    pop r8
    ldi r16, ILI9341_CMD_RAMWR                  ; start writing ro RAM
    rcall ili9341SendCommand

    mov r22, r10
    mov r23, r11
    ldi r17, 4
    cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN           ; SS low
    sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN       ; D high (DATA)
ili9341BitBlitStretch4_loopH:
      mov r20, xl                               ; preserve for next run
      mov r21, xh
      rcall ili9341BitBlitStretchNWriteLine     ; (r16, r17, r18, r19, r24, r25, X)
      mov xl, r20
      mov xh, r21
      rcall ili9341BitBlitStretchNWriteLine     ; (r16, r17, r18, r19, r24, r25, X)
      mov xl, r20
      mov xh, r21
      rcall ili9341BitBlitStretchNWriteLine     ; (r16, r17, r18, r19, r24, r25, X)
      mov xl, r20
      mov xh, r21
      rcall ili9341BitBlitStretchNWriteLine     ; (r16, r17, r18, r19, r24, r25, X)
      mov r24, r22
      mov r25, r23
      sbiw r25:r24, 1
      mov r22, r24
      mov r23, r25
    brne ili9341BitBlitStretch4_loopH
    sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN        ; SS high
    rcall ili9341EndSpi                      ; (R16)
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341BitBlitStretchNWriteLine

; @param r9:r8 width
; @param r17 repeat factor
; @param X source position of line
; @clobbers r16, r17, r18, r19, r24, r25, X

ili9341BitBlitStretchNWriteLine:
    mov r24, r8
    mov r25, r9
ili9341BitBlitStretchNWriteLine_loop1:
    ld r18, X+
    ld r19, X+
    push r17
ili9341BitBlitStretchNWriteLine_loop2:
        mov r16, r19
        rcall SPIHW_MasterTransfer           ; (R16)
        mov r16, r18
        rcall SPIHW_MasterTransfer           ; (R16)
        dec r17
      brne ili9341BitBlitStretchNWriteLine_loop2
    pop r17
    sbiw r25:r24, 1
  brne  ili9341BitBlitStretchNWriteLine_loop1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341SetAddressWindow
;
; @param r5:r4   X0
; @param r7:r6   Y0
; @param r9:r8   W
; @param r11:r10 H
; @clobbers R16, r20, r21

ili9341SetAddressWindow:
  rcall ili9341SetColumnAddress ; (R16, r20, r21)
  rcall ili9341SetRowAddress    ; (R16, r20, r21)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341SetColumnAddress
;
; @param r5:r4   X0
; @param r9:r8   W
; @clobbers R16, r20, r21

ili9341SetColumnAddress:
  ; calc XEnd (=X+W-1)
  mov r20, r8
  mov r21, r9
  add r20, r4
  adc r21, r5
  subi r20, 1
  sbci r21, 0

  ; send column address
  ldi r16, ILI9341_CMD_CASET
  rcall ili9341SendCommand     ; (R16)

  cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS low
  sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN   ; D high (DATA)

  ; Xstart
  mov r16, r5
  rcall SPIHW_MasterTransfer              ; (R16)
  mov r16, r4
  rcall SPIHW_MasterTransfer              ; (R16)
  ; Xend
  mov r16, r21
  rcall SPIHW_MasterTransfer              ; (R16)
  mov r16, r20
  rcall SPIHW_MasterTransfer              ; (R16)

  sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS high
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341SetRowAddress
;
; @param r7:r6   Y0
; @param r11:r10 H
; @clobbers R16, r20, r21

ili9341SetRowAddress:
  ; calc YEnd (=Y+H-1)
  mov r20, r10
  mov r21, r11
  add r20, r6
  adc r21, r7
  subi r20, 1
  sbci r21, 0

  ; send row address
  ldi r16, ILI9341_CMD_PASET
  rcall ili9341SendCommand                ; (R16)

  cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS low
  sbi ILI9341_DC_OUTPUT, ILI9341_DC_PIN   ; D high (DATA)

  ; Ystart
  mov r16, r7
  rcall SPIHW_MasterTransfer              ; (R16)
  mov r16, r6
  rcall SPIHW_MasterTransfer              ; (R16)
  ; Yend
  mov r16, r21
  rcall SPIHW_MasterTransfer              ; (R16)
  mov r16, r20
  rcall SPIHW_MasterTransfer              ; (R16)

  sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN       ; SS high
  ret
; @end






#endif ; AQH_AVR_ILI9341_GRAPHOPS_ASM

