; ---------------------------------------------------------------------------
; CTC Tests: Counter 16 Bits -> INT (Vector)
; (c) 2013 SyX
; ---------------------------------------------------------------------------

    include "firmware.i"
    include "hardware.i"
    include "supergrafx.i"
    include "macros.i"
    
; ---------------------------------------------------------------------------
    ORG  $4000
inicio
    ; Disable firmware and install Interrupt
    DI
    IM  2
    LD  A,$5F
    LD  I,A

    ; Set mode 1
    LD   BC,$7F8D
    OUT  (C),C

    ; Fill table $4100 - $4200 with $40
    LD  DE,$5F01
    LD  HL,$5F00
    LD  (HL),$50
    LD  BC,256
    LDIR
    
    ; Install Interrupt handler
    LD   A,$C3
    LD   HL,interrupt_handler
    LD   ($5050),A
    LD   ($5051),HL

    ; Set Vector lower byte to 0
    LD   BC,CTC_TIM0
    OUT  (C),0
    EI

    ; Copy font to $8000
    LD   HL,font
    LD   DE,$8000
    LD   BC,end_font - font
    LDIR

    ; Initialize timer
    LD   HL,(init_counter_cnt)
    LD   (counter_cnt),HL

    ; Print timer off
    LD   IY,txt_on
    CALL print_string
    
    ; Wait to no key is pressed
    CALL wait_keyboard_free
    
.main_loop
    CALL wait_vblank
    HALT
    CALL read_keyboard
    OR   A
    JR   Z,.main_loop
    ; Comprobar teclas
.check_up
    BIT  JOY_UP,A
    JR   Z,.check_down
    LD   A,(.sm_timer_enable + 1)
    OR   A
    JP   Z,.end_main_loop

    LD   HL,(counter_cnt)
;    INC  HL
.sm_add
    LD   BC,1
    ADD  HL,BC
    LD   (counter_cnt),HL

    ; Program new time constant in the CTC
    LD   BC,CTC_TIM2
    LD   A,(start_counter)
    OUT  (C),A  ; Enable Timer 
    OUT  (C),L  ; Set new time constant
    INC  BC
    OUT  (C),A  ; Enable Timer 
    OUT  (C),H  ; Set new time constant

    ; Convert value
    LD   DE,txt_on_timer
    CALL bin2dec
    
    LD   IY,txt_on
    CALL print_string
    
    JP   .end_main_loop

.check_down
    BIT  JOY_DOWN,A
    JR   Z,.check_space
    LD   A,(.sm_timer_enable + 1)
    OR   A
    JP   Z,.end_main_loop

    LD   HL,(counter_cnt)
;    DEC  HL
.sm_sub
    LD   BC,1
    SBC  HL,BC
    LD   (counter_cnt),HL

    ; Program new time constant in the CTC
    LD   BC,CTC_TIM2
    LD   A,(start_counter)
    OUT  (C),A  ; Enable Timer 
    OUT  (C),L  ; Set new time constant
    INC  BC
    OUT  (C),A  ; Enable Timer 
    OUT  (C),H  ; Set new time constant

    ; Convert value
    LD   DE,txt_on_timer
    CALL bin2dec
    
    LD   IY,txt_on
    CALL print_string
    JP   .end_main_loop

.check_space
    BIT  JOY_FIRE2,A
    JP   Z,.main_loop
.sm_timer_enable
    LD   A,$00
    OR   A
    JR   Z,.start_timer
.stop_timer
    CPL
    LD   (.sm_timer_enable + 1),A

    ; Disable CTC
    LD   BC,CTC_TIM2
    LD   A,(stop_counter)
    OUT  (C),A  ; Disable Timer 
    INC  BC
    OUT  (C),A  ; Disable Timer 

    LD   HL,$0F0F
    LD   (txt_on_timer),HL
    LD   (txt_on_timer + 2),HL
    LD   A,H
    LD   (txt_on_timer + 4),A
    LD   IY,txt_on
    CALL print_string
    JR   .end_main_loop

.start_timer
    CPL
    LD   (.sm_timer_enable + 1),A

    ; Enable CTC
    LD   HL,(counter_cnt)
    LD   BC,CTC_TIM2
    LD   A,(start_counter)
    OUT  (C),A  ; Enable Timer 
    OUT  (C),L  ; Set new time constant
    INC  BC
    OUT  (C),A  ; Enable Timer 
    OUT  (C),H  ; Set new time constant

    LD   DE,txt_on_timer
    CALL bin2dec
    
    LD   IY,txt_on
    CALL print_string

.end_main_loop
    CALL wait_keyboard_free
    JP   .main_loop

counter_cnt
    DEFW 0

start_counter
    DEFB CTC_START_ICOUNTER     ; %11110111

stop_counter
    DEFB CTC_STOP_CHANNEL       ; %00000011

init_counter_cnt
    DEFW 1

; ---------------------------------------------------------------------------
interrupt_handler
    PUSH BC
    PUSH AF
    LD   BC,$7F10
    OUT  (C),C
    LD   A,R
    OR   $40
    OUT  (C),A 
    POP  AF
    POP  BC
    EI
    RETI

; ---------------------------------------------------------------------------
; Wait vblank
wait_vblank
    WAIT_VBL
    RET

; ---------------------------------------------------------------------------
; Wait until no key is pressed
wait_keyboard_free
.loop_keyboard_free
    CALL wait_vblank
    HALT
    CALL anykey_press
    JR   C,.loop_keyboard_free
    RET
; ---------------------------------------------------------------------------
; Test if any key is pressed and mark the Carry flag.
; ---------------------------------------------------------------------------
anykey_press
    INIT_PSG_FOR_SCANKEYS
    LD   C,%01000000            ; Key line 0 - 9
.loop_anykey_press
    LD   B,>PPI_C
    OUT  (C),C                  ; Send Key line
    LD   B,>PPI_A
    IN   A,(C)                  ; Read Key line
    CPL
    AND  A
    JR   NZ,.key_press
    INC  C
    LD   A,%01001010
    CP   C
    JR   NZ,.loop_anykey_press
    JR   .no_key_press
.key_press
    SCF
    JR   .end_anykey_press
.no_key_press
    AND  A
.end_anykey_press
    RESTORE_PSG_OF_SCANKEYS
    RET
    
; ---------------------------------------------------------------------------
; Read keyboard and joystick
; RESULT:
;    A : %s3chdrlu (SPACE, TAB, COPY, SHIFT + Right/Left, Down, Right, Left, Up)
; ---------------------------------------------------------------------------
read_keyboard
    ; Select the PSG IOPORT_A
    LD   BC,PPI_A + PSG_IOPORT_A
    OUT  (C),C

    ; Operation Select PSG Register and Joystick 0 key Line 
    LD   BC,PPI_C + PPI_PSG_SELECT              ; + JOY0 <--- Puto ERROR!!! xDDD
    OUT  (C),C

    ; PSG Inactive (Needed in CPC+, because the PPI emulation do not automatically
    ; resets the Ports A, B and C to $00, when PPI Control changes (bit 7 set)
    DEFB $ED,$71                                ; OUT (C),0 

    ; Set the PPI_A in input mode
    LD   BC,PPI_CONTROL + PPI_A_INPUT
    OUT  (C),C

    LD   A,$FF
.read_cursor_keys
    ; Check Cursors Up, Down and Right
    LD   BC,PPI_C + PPI_PSG_READ + KEY_LINE0
    OUT  (C),C                  
    LD   B,>PPI_A
    IN   B,(C)                                  ; B = byte received
.cursor_up
    BIT  CURSOR_UP,B
    JR   NZ,.cursor_right
    RES  JOY_UP,A
.cursor_right
    BIT  CURSOR_RIGHT,B
    JR   NZ,.cursor_down
    RES  JOY_RIGHT,A
.cursor_down
    BIT  CURSOR_DOWN,B
    JR   NZ,.cursor_left
    RES  JOY_DOWN,A
.cursor_left
    ; Check Cursor Left
    LD   BC,PPI_C + PPI_PSG_READ + KEY_LINE1
    OUT  (C),C                  
    LD   B,>PPI_A
    IN   B,(C)                                  ; B = byte received
    BIT  CURSOR_LEFT,B
    JR   NZ,.check_space
    RES  JOY_LEFT,A

.check_space
    LD   BC,PPI_C + PPI_PSG_READ + KEY_LINE5
    OUT  (C),C                  
    LD   B,>PPI_A
    IN   B,(C)                                  ; B = byte received
    BIT  KEY_SPACE,B                            ; NTSC/PAL
    JR   NZ,.end_check_keys
    RES  JOY_FIRE2,A
    
.end_check_keys
    ; Set the PPI_A in output mode
    LD   BC,PPI_CONTROL + PPI_A_OUTPUT
    OUT  (C),C

    ; PSG Inactive (Needed in CPC+)
    DEC  B                                      ; B = PPI_C
    DEFB $ED,$71                                ; OUT (C),0 

    CPL
    RET

; ---------------------------------------------------------------------------
; Convert from binary to ascii decimal string (Baze)
; ENTRY:
;    HL : Value to convert
;    DE : Pointer to the string
; ---------------------------------------------------------------------------
bin2dec
.convierte_decenas_millares
    LD   BC,-10000
    CALL .bin2dec1
.convierte_millares
    LD   BC,-1000
    CALL .bin2dec1
.convierte_centenas
    LD   BC,-100
    CALL .bin2dec1
.convierte_decenas
    LD   C,-10
    CALL .bin2dec1
.convierte_unidades
    LD   C,B
.bin2dec1
    LD   A,255 ;T_0 - 1
.bin2dec2
    INC  A
    ADD  HL,BC
    JR   C,.bin2dec2
    SBC  HL,BC
    LD   (DE),A
    INC  DE
    RET

; ---------------------------------------------------------------------------
; Print a string finished in 255
; IY : String
print_string
    LD   DE,$C000
;    LD   E,(IY + 0)
;    INC  IY
;    LD   D,(IY + 0)                         ; Screen address
;    INC  IY
.loop_print_string
    LD   A,(IY + 0)                         ; Get Tile number
    CP   255
    RET  Z                                  ; Finish???
    
    INC  IY                                 ; Tilemap++

    ; Print tile
    PUSH DE
    CALL draw_tilenumber
    POP  DE
    
    ; Next screen address
    INC  DE
    INC  DE
    
    JR   .loop_print_string

; --------------------------------------------------------------------------- 
;  A : Tile number
; DE : Screen address
draw_tilenumber
    ; Get the tile address ($8000 + tile_number << 4) 
    LD   H,%00001000
    SLA  A
    RL   H
    RLA
    RL   H
    RLA
    RL   H
    RLA
    RL   H
    LD   L,A                ; HL hold tile address

; HL : Tile address
; DE : Screen address
draw_tile
    ; 1º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    SET  3,D
    ; 2º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    SET  4,D
    ; 4º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    RES  3,D
    ; 3º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    SET  5,D
    ; 7º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    RES  4,D
    ; 5º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    SET  3,D
    ; 6º Scanline
    LDI
    LDI
    DEC  E
    DEC  E
    SET  4,D
    ; 8º Scanline
    LDI
    LDI

    RET
    
; ---------------------------------------------------------------------------
txt_on
txt_on_timer
    DEFB $0f,$0f,$0f,$0f,$0f
    DEFB 255

font
    incbin 'recursos/font.bin'
end_font

; ---------------------------------------------------------------------------
    END
